Дистанционный гибер из реал

This commit is contained in:
Tornado Tech
2024-05-08 20:15:05 +10:00
parent a0a2e8fabf
commit 0f6e73831a
16 changed files with 282 additions and 59 deletions

View File

@@ -0,0 +1,8 @@
namespace Content.Server._CP14.Magic;
[RegisterComponent]
public sealed partial class CPMagicSpellComponent : Component
{
[DataField, ViewVariables(VVAccess.ReadWrite)]
public List<CPMagicEffectPrototype> Effects = new();
}

View File

@@ -5,11 +5,18 @@ namespace Content.Server._CP14.Magic;
[RegisterComponent]
public sealed partial class CPMagicSpellContainerComponent : Component
{
public readonly EntProtoId BaseSpellEffectEntity = "CPBaseSpellEntity";
[DataField, ViewVariables(VVAccess.ReadWrite)]
public List<ProtoId<CPMagicEffectPrototype>> Effects = new();
[DataField, ViewVariables]
public List<CPMagicEffectPrototype> EffectPrototypes = new ();
[DataField, ViewVariables(VVAccess.ReadWrite)]
public float MaximumCompleteness = 1f;
[DataField, ViewVariables]
public float TotalCompleteness;
[DataField, ViewVariables]
public TimeSpan TotalCastTime;
}

View File

@@ -0,0 +1,89 @@
using System.Diagnostics.CodeAnalysis;
using Content.Shared._CP14.Magic.Events;
using Content.Shared.DoAfter;
using Content.Shared.Hands.Components;
using Content.Shared.Verbs;
namespace Content.Server._CP14.Magic;
public sealed partial class CPMagicSpellContainerSystem
{
private void InitializeCast()
{
SubscribeLocalEvent<CPMagicSpellContainerComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerb);
SubscribeLocalEvent<CPMagicSpellContainerComponent, CPMagicCastDoAfterEvent>(OnCast);
}
private void OnGetVerb(Entity<CPMagicSpellContainerComponent> container, ref GetVerbsEvent<AlternativeVerb> args)
{
var user = args.User;
args.Verbs.Add(new AlternativeVerb
{
Text = "Get spell",
Disabled = container.Comp.Effects.Count == 0,
Priority = 10,
Act = () =>
{
StartCast(container, user);
}
});
}
private void OnCast(Entity<CPMagicSpellContainerComponent> container, ref CPMagicCastDoAfterEvent args)
{
if (args.Handled || args.Cancelled || args.Target is null)
return;
Cast(container, args.Target.Value);
args.Handled = true;
}
public void StartCast(Entity<CPMagicSpellContainerComponent> container, EntityUid caster)
{
if (!CastValidate(container, caster, out _))
return;
var doAfterArgs = new DoAfterArgs(EntityManager, caster, container.Comp.TotalCastTime, new CPMagicCastDoAfterEvent(), target: caster, used: container, eventTarget: container)
{
BreakOnDamage = true,
BreakOnMove = true,
MovementThreshold = 0.5f,
CancelDuplicate = false,
};
_doAfter.TryStartDoAfter(doAfterArgs);
}
public void Cast(Entity<CPMagicSpellContainerComponent> container, EntityUid caster)
{
if (!CastValidate(container, caster, out var hand))
return;
var entity = Spawn(BaseSpellItemEntity, _transform.GetMapCoordinates(container));
var spell = EnsureComp<CPMagicSpellComponent>(entity);
spell.Effects = new List<CPMagicEffectPrototype>(container.Comp.EffectPrototypes);
_hands.TryPickup(caster, entity, hand);
}
private bool CastValidate(Entity<CPMagicSpellContainerComponent> container, EntityUid caster, [NotNullWhen(true)] out Hand? hand)
{
hand = default;
if (container.Comp.TotalCompleteness > container.Comp.MaximumCompleteness)
{
_popup.PopupEntity("Too much complicated", container);
return false;
}
if (!_hands.TryGetEmptyHand(caster, out hand))
{
_popup.PopupEntity("The spell can't fit in your hand", container);
return false;
}
return true;
}
}

View File

@@ -0,0 +1,43 @@
using Content.Server._CP14.Magic.Events;
namespace Content.Server._CP14.Magic;
public sealed partial class CPMagicSpellContainerSystem
{
private void InitializeHash()
{
SubscribeLocalEvent<CPMagicSpellContainerComponent, ComponentStartup>(OnStartup);
SubscribeLocalEvent<CPMagicSpellContainerComponent, CPMagicSpellContainerListUpdatedEvent>(OnListUpdated);
}
private void OnStartup(Entity<CPMagicSpellContainerComponent> container, ref ComponentStartup args)
{
RaiseListUpdated(container);
}
private void OnListUpdated(Entity<CPMagicSpellContainerComponent> container, ref CPMagicSpellContainerListUpdatedEvent args)
{
container.Comp.EffectPrototypes = new List<CPMagicEffectPrototype>();
container.Comp.TotalCompleteness = 0f;
container.Comp.TotalCastTime = TimeSpan.Zero;
foreach (var effectId in container.Comp.Effects)
{
if (!_prototype.TryIndex(effectId, out var prototype))
{
_sawmill.Error($"Impossible to find a prototype for {effectId}");
return;
}
container.Comp.EffectPrototypes.Add(prototype);
container.Comp.TotalCompleteness += prototype.Complexity;
container.Comp.TotalCastTime += prototype.CastTime;
}
}
private void RaiseListUpdated(Entity<CPMagicSpellContainerComponent> container)
{
var ev = new CPMagicSpellContainerListUpdatedEvent();
RaiseLocalEvent(container, ev);
}
}

View File

@@ -0,0 +1,25 @@
using Content.Shared.Interaction;
namespace Content.Server._CP14.Magic;
public sealed partial class CPMagicSpellContainerSystem
{
private void InitializeSpell()
{
SubscribeLocalEvent<CPMagicSpellComponent, AfterInteractEvent>(OnInteract);
}
private void OnInteract(Entity<CPMagicSpellComponent> spell, ref AfterInteractEvent args)
{
var entity = Spawn(BaseSpellEffectEntity, args.ClickLocation.ToMap(EntityManager, _transform));
foreach (var effect in spell.Comp.Effects)
{
EntityManager.AddComponents(entity, effect.Components);
}
var ev = new CPMagicCastedEvent(args.User, args.Target, args.ClickLocation);
RaiseLocalEvent(entity, ev);
Del(spell);
}
}

View File

@@ -1,64 +1,33 @@
using Content.Server.Popups;
using Content.Shared.Verbs;
using Content.Server.DoAfter;
using Content.Server.Hands.Systems;
using Content.Server.Popups;
using Robust.Server.GameObjects;
using Robust.Shared.Prototypes;
namespace Content.Server._CP14.Magic;
public sealed class CPMagicSpellContainerSystem : EntitySystem
public sealed partial class CPMagicSpellContainerSystem : EntitySystem
{
[Dependency] private readonly DoAfterSystem _doAfter = default!;
[Dependency] private readonly IPrototypeManager _prototype = default!;
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly HandsSystem _hands = default!;
[Dependency] private readonly TransformSystem _transform = default!;
[Dependency] private readonly PopupSystem _popup = default!;
public readonly EntProtoId BaseSpellItemEntity = "CPBSpellItemEntity";
public readonly EntProtoId BaseSpellEffectEntity = "CPBaseSpellEntity";
private ISawmill _sawmill = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CPMagicSpellContainerComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerb);
}
_sawmill = _logManager.GetSawmill("cp14_magic_spell_container");
private void OnGetVerb(Entity<CPMagicSpellContainerComponent> container, ref GetVerbsEvent<AlternativeVerb> args)
{
var user = args.User;
args.Verbs.Add(new AlternativeVerb
{
Text = "cast",
Disabled = container.Comp.Effects.Count == 0,
Priority = 10,
Act = () =>
{
Cast(container, user);
}
});
}
public void Cast(Entity<CPMagicSpellContainerComponent> container, EntityUid caster)
{
var effectPrototypes = new List<CPMagicEffectPrototype>();
var complexity = 0f;
foreach (var effectId in container.Comp.Effects)
{
if (!_prototype.TryIndex(effectId, out var prototype))
{
_popup.PopupEntity("Fuck!", container);
return;
}
complexity += prototype.Complexity;
effectPrototypes.Add(prototype);
}
if (complexity > container.Comp.MaximumCompleteness)
{
_popup.PopupEntity("Too much complicated", container);
return;
}
var entity = Spawn(container.Comp.BaseSpellEffectEntity, Transform(container).Coordinates);
foreach (var effect in effectPrototypes)
{
EntityManager.AddComponents(entity, effect.Components);
}
InitializeHash();
InitializeCast();
InitializeSpell();
}
}

View File

@@ -0,0 +1,16 @@
using Content.Shared.Damage;
namespace Content.Server._CP14.Magic.Effects.Damage;
[RegisterComponent]
public sealed partial class CPCastEffectDamageComponent : Component
{
[DataField(required: true)]
public DamageSpecifier Damage = default!;
[DataField]
public bool IgnoreResistances;
[DataField]
public bool InterruptsDoAfters = true;
}

View File

@@ -0,0 +1,24 @@
using Content.Shared.Damage;
namespace Content.Server._CP14.Magic.Effects.Damage;
public sealed class CPCastEffectDamageSystem : EntitySystem
{
[Dependency] private readonly DamageableSystem _damageable = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<CPCastEffectDamageComponent, CPMagicCastedEvent>(OnCasted);
}
private void OnCasted(Entity<CPCastEffectDamageComponent> effect, ref CPMagicCastedEvent args)
{
if (args.Target is null)
return;
_damageable.TryChangeDamage(args.Target, effect.Comp.Damage, effect.Comp.IgnoreResistances,
effect.Comp.InterruptsDoAfters);
}
}

View File

@@ -0,0 +1,10 @@
using Robust.Shared.Map;
namespace Content.Server._CP14.Magic;
public sealed class CPMagicCastedEvent(EntityUid caster, EntityUid? target, EntityCoordinates coordinates) : EntityEventArgs
{
public readonly EntityUid Caster = caster;
public readonly EntityUid? Target = target;
public readonly EntityCoordinates Coordinates = coordinates;
}

View File

@@ -0,0 +1,6 @@
namespace Content.Server._CP14.Magic.Events;
public sealed class CPMagicSpellContainerListUpdatedEvent : EntityEventArgs
{
}

View File

@@ -13,4 +13,7 @@ public sealed partial class CPMagicEffectPrototype : IPrototype
[DataField]
public float Complexity = 1f;
[DataField]
public TimeSpan CastTime = TimeSpan.Zero;
}

View File

@@ -0,0 +1,7 @@
using Content.Shared.DoAfter;
using Robust.Shared.Serialization;
namespace Content.Shared._CP14.Magic.Events;
[Serializable, NetSerializable]
public sealed partial class CPMagicCastDoAfterEvent : SimpleDoAfterEvent;

View File

@@ -0,0 +1,9 @@
- type: CPMagicEffect
id: CPDamageGibber
complexity: 100
components:
- type: CPCastEffectDamage
damage:
types:
Blunt: 20000
ignoreResistances: true

View File

@@ -1,13 +1,9 @@
- type: CPMagicEffect
id: CPPointLight
complexity: 0.5
castTime: 5
components:
- type: PointLight
radius: 10
energy: 10
color: "#ffffff"
- type: CPMagicEffect
id: CPPaintPointLightRed
components:
- type: PointLight
color: "#ff0000"

View File

@@ -1,5 +1,14 @@
- type: entity
parent: BaseItem
id: CPBSpellItemEntity
name: spell
noSpawn: true
components:
- type: Unremoveable
- type: TimedDespawn
lifetime: 5
- type: entity
id: CPBaseSpellEntity
name: magic entity
noSpawn: true

View File

@@ -4,7 +4,9 @@
name: charm
description: The simplest storage for your spell
components:
- type: DoAfter
- type: CPMagicSpellContainer
maximumCompleteness: 999
effects:
- CPPointLight
- CPPaintPointLightRed
- CPDamageGibber