diff --git a/Content.Shared/StatusEffectNew/StatusEffectSystem.Relay.cs b/Content.Shared/StatusEffectNew/StatusEffectSystem.Relay.cs index 6d97a75edd..0bf02b6cd6 100644 --- a/Content.Shared/StatusEffectNew/StatusEffectSystem.Relay.cs +++ b/Content.Shared/StatusEffectNew/StatusEffectSystem.Relay.cs @@ -1,3 +1,5 @@ +using Content.Shared.Damage; +using Content.Shared.Damage.Events; using Content.Shared.StatusEffectNew.Components; using Robust.Shared.Player; @@ -7,6 +9,10 @@ public abstract partial class SharedStatusEffectsSystem { protected void InitializeRelay() { + //CP14 Zone + SubscribeLocalEvent(RelayStatusEffectEvent); + //CP14 Zone end + SubscribeLocalEvent(RelayStatusEffectEvent); SubscribeLocalEvent(RelayStatusEffectEvent); } diff --git a/Content.Shared/_CP14/MagicSpell/Spells/CP14SpellApplyStatusEffect.cs b/Content.Shared/_CP14/MagicSpell/Spells/CP14SpellApplyStatusEffect.cs new file mode 100644 index 0000000000..ae9b514549 --- /dev/null +++ b/Content.Shared/_CP14/MagicSpell/Spells/CP14SpellApplyStatusEffect.cs @@ -0,0 +1,29 @@ +using Content.Shared.StatusEffectNew; +using Robust.Shared.Prototypes; + +namespace Content.Shared._CP14.MagicSpell.Spells; + +public sealed partial class CP14SpellApplyStatusEffect : CP14SpellEffect +{ + [DataField(required: true)] + public EntProtoId StatusEffect = default; + + [DataField(required: true)] + public TimeSpan Duration = TimeSpan.FromSeconds(1f); + + [DataField] + public bool Refresh = true; + + public override void Effect(EntityManager entManager, CP14SpellEffectBaseArgs args) + { + if (args.Target is null) + return; + + var effectSys = entManager.System(); + + if (!Refresh) + effectSys.TryAddStatusEffectDuration(args.Target.Value, StatusEffect, Duration); + else + effectSys.TrySetStatusEffectDuration(args.Target.Value, StatusEffect, Duration); + } +} diff --git a/Content.Shared/_CP14/StatusEffect/CP14ApplySpellStatusEffectComponent.cs b/Content.Shared/_CP14/StatusEffect/CP14ApplySpellStatusEffectComponent.cs new file mode 100644 index 0000000000..d3cbd6fe6e --- /dev/null +++ b/Content.Shared/_CP14/StatusEffect/CP14ApplySpellStatusEffectComponent.cs @@ -0,0 +1,24 @@ +using Content.Shared._CP14.MagicSpell.Spells; +using Robust.Shared.GameStates; + +namespace Content.Shared._CP14.StatusEffect; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentPause] +[Access(typeof(CP14ApplySpellStatusEffectSystem))] +public sealed partial class CP14ApplySpellStatusEffectComponent : Component +{ + [DataField(serverOnly: true)] + public List StartEffect = new(); + + [DataField(serverOnly: true)] + public List EndEffect = new(); + + [DataField(serverOnly: true)] + public List UpdateEffect = new(); + + [DataField] + public TimeSpan UpdateFrequency = TimeSpan.FromSeconds(1f); + + [DataField, AutoPausedField] + public TimeSpan NextUpdateTime = TimeSpan.Zero; +} diff --git a/Content.Shared/_CP14/StatusEffect/CP14ApplySpellStatusEffectSystem.cs b/Content.Shared/_CP14/StatusEffect/CP14ApplySpellStatusEffectSystem.cs new file mode 100644 index 0000000000..5877ba26ad --- /dev/null +++ b/Content.Shared/_CP14/StatusEffect/CP14ApplySpellStatusEffectSystem.cs @@ -0,0 +1,74 @@ +using Content.Shared._CP14.MagicSpell.Spells; +using Content.Shared.Damage; +using Content.Shared.StatusEffectNew; +using Content.Shared.StatusEffectNew.Components; +using Robust.Shared.Timing; + +namespace Content.Shared._CP14.StatusEffect; + +public sealed partial class CP14ApplySpellStatusEffectSystem : EntitySystem +{ + [Dependency] private readonly IGameTiming _timing = default!; + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(SpellEffectApply); + SubscribeLocalEvent(SpellEffectRemove); + + SubscribeLocalEvent>(OnDamageModify); + } + + private void OnDamageModify(Entity ent, ref StatusEffectRelayedEvent args) + { + DamageSpecifier newDamage = new(); + foreach (var (type, damage) in args.Args.Damage.DamageDict) + { + var dmg = damage * ent.Comp.GlobalDefence; + + if (ent.Comp.Defence is not null && ent.Comp.Defence.TryGetValue(type, out var typeDefence)) + dmg *= typeDefence; + + newDamage.DamageDict[type] = dmg; + } + args.Args.Damage = newDamage; + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var ent, out var spellEffect, out var statusEffect)) + { + if (spellEffect.NextUpdateTime > _timing.CurTime) + continue; + + if (statusEffect.AppliedTo is null) + continue; + + spellEffect.NextUpdateTime += spellEffect.UpdateFrequency; + + foreach (var effect in spellEffect.UpdateEffect) + { + effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(null, null, statusEffect.AppliedTo, Transform(statusEffect.AppliedTo.Value).Coordinates)); + } + } + } + + private void SpellEffectApply(Entity ent, ref StatusEffectAppliedEvent args) + { + foreach (var effect in ent.Comp.StartEffect) + { + effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(null, null, args.Target, Transform(args.Target).Coordinates)); + } + } + + private void SpellEffectRemove(Entity ent, ref StatusEffectRemovedEvent args) + { + foreach (var effect in ent.Comp.EndEffect) + { + effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(null, null, args.Target, Transform(args.Target).Coordinates)); + } + } +} diff --git a/Content.Shared/_CP14/StatusEffect/CP14DamageModifierStatusEffect.cs b/Content.Shared/_CP14/StatusEffect/CP14DamageModifierStatusEffect.cs new file mode 100644 index 0000000000..b91879961a --- /dev/null +++ b/Content.Shared/_CP14/StatusEffect/CP14DamageModifierStatusEffect.cs @@ -0,0 +1,16 @@ +using Content.Shared.Damage.Prototypes; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; + +namespace Content.Shared._CP14.StatusEffect; + +[RegisterComponent, NetworkedComponent] +[Access(typeof(CP14ApplySpellStatusEffectSystem))] +public sealed partial class CP14DamageModifierStatusEffectComponent : Component +{ + [DataField] + public Dictionary, float>? Defence = null; + + [DataField] + public float GlobalDefence = 1f; +} diff --git a/Resources/Prototypes/_CP14/Alerts/status_effect.yml b/Resources/Prototypes/_CP14/Alerts/status_effect.yml new file mode 100644 index 0000000000..e02a919650 --- /dev/null +++ b/Resources/Prototypes/_CP14/Alerts/status_effect.yml @@ -0,0 +1,11 @@ +- type: alert + id: CP14Glowing + icons: + - sprite: _CP14/Actions/Spells/light.rsi + state: sphere_of_light + +- type: alert + id: CP14MagicArmor + icons: + - sprite: _CP14/Actions/Spells/meta.rsi + state: magic_armor \ No newline at end of file diff --git a/Resources/Prototypes/_CP14/Entities/Actions/Spells/Light/sphere_of_light.yml b/Resources/Prototypes/_CP14/Entities/Actions/Spells/Light/sphere_of_light.yml index 9d497e5564..52a6a9d0b5 100644 --- a/Resources/Prototypes/_CP14/Entities/Actions/Spells/Light/sphere_of_light.yml +++ b/Resources/Prototypes/_CP14/Entities/Actions/Spells/Light/sphere_of_light.yml @@ -15,9 +15,9 @@ - !type:CP14SpellSpawnEntityOnTarget spawns: - CP14ImpactEffectSphereOfLight - - !type:CP14SpellSpawnInHandEntity - spawns: - - CP14SphereOfLight + - !type:CP14SpellApplyStatusEffect + statusEffect: CP14StatusEffectGlowing + duration: 120 - type: CP14MagicEffectVerbalAspect startSpeech: "Appare in manu tua..." endSpeech: "sphaera lucis" @@ -28,8 +28,15 @@ icon: sprite: _CP14/Actions/Spells/light.rsi state: sphere_of_light - - type: InstantAction - event: !type:CP14DelayedInstantActionEvent + - type: TargetAction + range: 5 + - type: EntityTargetAction + whitelist: + components: + - MobState + - Item + - Anchorable + event: !type:CP14DelayedEntityTargetActionEvent cooldown: 30 castDelay: 0.5 breakOnMove: false @@ -60,43 +67,6 @@ color: "#efedff" shader: unshaded -- type: entity - id: CP14SphereOfLight - name: Sphere of light - parent: BaseItem - description: A lump of bright light in the shape of a sphere. - categories: [ ForkFiltered ] - components: - - type: TimedDespawn - lifetime: 120 # 2 min - - type: Sprite - sprite: _CP14/Effects/Magic/sphere_of_light.rsi - noRot: true - layers: - - state: icon - shader: unshaded - - type: Item - size: Ginormous - inhandVisuals: - left: - - state: inhand-left-unshaded - shader: unshaded - right: - - state: inhand-right-unshaded - shader: unshaded - - type: LandAtCursor - - type: MovementIgnoreGravity - - type: PointLight - radius: 5.0 - energy: 1 - color: "#efedff" - - type: Damageable - - type: EmitSoundOnLand - sound: - path: /Audio/Effects/drop.ogg - params: - volume: -100 #Yes, it's stupid, but it's easier - - type: entity parent: CP14BaseSpellScrollLight id: CP14SpellScrollSphereOfLight diff --git a/Resources/Prototypes/_CP14/Entities/Actions/Spells/Meta/mana_armor.yml b/Resources/Prototypes/_CP14/Entities/Actions/Spells/Meta/mana_armor.yml new file mode 100644 index 0000000000..5b8c6c6324 --- /dev/null +++ b/Resources/Prototypes/_CP14/Entities/Actions/Spells/Meta/mana_armor.yml @@ -0,0 +1,37 @@ +- type: entity + id: CP14ActionSpellMagicArmor + parent: CP14ActionSpellBase + name: Magic Armor + description: You surround the target with a short-lived magical barrier that absorbs some of the damage it receives. + components: + - type: CP14MagicEffectCastSlowdown + speedMultiplier: 0.5 + - type: CP14MagicEffectManaCost + manaCost: 15 + - type: CP14MagicEffectCastingVisual + proto: CP14RuneManaTrance + - type: CP14MagicEffect + magicType: Fire + effects: + - !type:CP14SpellSpawnEntityOnTarget + spawns: + - CP14ImpactEffectManaGift + - !type:CP14SpellApplyStatusEffect + statusEffect: CP14StatusEffectMagicArmor + duration: 20 + - type: Action + icon: + sprite: _CP14/Actions/Spells/meta.rsi + state: magic_armor + - type: TargetAction + range: 5 + - type: EntityTargetAction + whitelist: + components: + - MobState + - Item + - Anchorable + event: !type:CP14DelayedEntityTargetActionEvent + cooldown: 10 + castDelay: 1.0 + breakOnMove: false \ No newline at end of file diff --git a/Resources/Prototypes/_CP14/Entities/StatusEffects/misc.yml b/Resources/Prototypes/_CP14/Entities/StatusEffects/misc.yml new file mode 100644 index 0000000000..b105b49bd8 --- /dev/null +++ b/Resources/Prototypes/_CP14/Entities/StatusEffects/misc.yml @@ -0,0 +1,45 @@ +- type: entity + id: CP14StatusEffectGlowing + components: + - type: StatusEffect + alert: CP14Glowing + - type: Sprite + drawdepth: Effects + sprite: _CP14/Effects/Magic/sphere_of_light.rsi + offset: 0, 1 + noRot: true + layers: + - state: icon + shader: unshaded + - type: PointLight + radius: 5.0 + energy: 1 + color: "#efedff" + +- type: entity + id: CP14StatusEffectMagicArmor + components: + - type: StatusEffect + alert: CP14MagicArmor + - type: Sprite + drawdepth: Mobs + sprite: _CP14/Effects/Magic/cast_rune.rsi + noRot: true + layers: + - state: sphere + shader: unshaded + color: "#5096d488" + - state: circle_increase + sprite: _CP14/Effects/Magic/cast_impact.rsi + shader: unshaded + color: "#74eaf222" + - type: PointLight + radius: 2.5 + energy: 0.9 + color: "#5096d4" + - type: CP14DamageModifierStatusEffect + globalDefence: 0.6 + #defence: #TODO When stone armor spell appears, divide responsibilities: magical armor protects against elemental damage, stone armor protects against physical damage. + # Cold: 0.5 + # Heat: 0.5 + # Shock: 0.5 \ No newline at end of file diff --git a/Resources/Prototypes/_CP14/Skill/Basic/metamagic.yml b/Resources/Prototypes/_CP14/Skill/Basic/metamagic.yml index 247891f258..b8ca138775 100644 --- a/Resources/Prototypes/_CP14/Skill/Basic/metamagic.yml +++ b/Resources/Prototypes/_CP14/Skill/Basic/metamagic.yml @@ -153,6 +153,20 @@ - !type:NeedPrerequisite prerequisite: MetamagicT2 +- type: cp14Skill + id: CP14ActionSpellMagicArmor + skillUiPosition: 8, 4 + tree: Metamagic + icon: + sprite: _CP14/Actions/Spells/meta.rsi + state: magic_armor + effects: + - !type:AddAction + action: CP14ActionSpellMagicArmor + restrictions: + - !type:NeedPrerequisite + prerequisite: MetamagicT2 + # T3 - type: cp14Skill diff --git a/Resources/Textures/_CP14/Actions/Spells/meta.rsi/magic_armor.png b/Resources/Textures/_CP14/Actions/Spells/meta.rsi/magic_armor.png new file mode 100644 index 0000000000..56d6d83491 Binary files /dev/null and b/Resources/Textures/_CP14/Actions/Spells/meta.rsi/magic_armor.png differ diff --git a/Resources/Textures/_CP14/Actions/Spells/meta.rsi/meta.json b/Resources/Textures/_CP14/Actions/Spells/meta.rsi/meta.json index 8ba88a282d..08186a4bf0 100644 --- a/Resources/Textures/_CP14/Actions/Spells/meta.rsi/meta.json +++ b/Resources/Textures/_CP14/Actions/Spells/meta.rsi/meta.json @@ -13,6 +13,9 @@ { "name": "counter_spell_small" }, + { + "name": "magic_armor" + }, { "name": "magic_music" }, diff --git a/Resources/Textures/_CP14/Effects/Magic/cast_rune.rsi/meta.json b/Resources/Textures/_CP14/Effects/Magic/cast_rune.rsi/meta.json index 4044ea30de..0dd2414546 100644 --- a/Resources/Textures/_CP14/Effects/Magic/cast_rune.rsi/meta.json +++ b/Resources/Textures/_CP14/Effects/Magic/cast_rune.rsi/meta.json @@ -66,6 +66,17 @@ 0.2 ] ] + }, + { + "name": "sphere", + "delays": [ + [ + 0.2, + 0.2, + 0.2, + 0.2 + ] + ] } ] } diff --git a/Resources/Textures/_CP14/Effects/Magic/cast_rune.rsi/sphere.png b/Resources/Textures/_CP14/Effects/Magic/cast_rune.rsi/sphere.png new file mode 100644 index 0000000000..5cfa008092 Binary files /dev/null and b/Resources/Textures/_CP14/Effects/Magic/cast_rune.rsi/sphere.png differ