2024-06-08 13:01:49 +00:00
|
|
|
|
using System.Linq;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
using System.Numerics;
|
2024-06-20 16:24:10 +00:00
|
|
|
|
using Content.Server._White.Cult;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
using Content.Server._White.IncorporealSystem;
|
2024-07-01 11:23:51 +00:00
|
|
|
|
using Content.Server._White.Wizard.Charging;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
using Content.Server._White.Wizard.Magic.Amaterasu;
|
|
|
|
|
|
using Content.Server._White.Wizard.Magic.Other;
|
2024-06-22 12:55:50 +00:00
|
|
|
|
using Content.Server._White.Wizard.Magic.TeslaProjectile;
|
2024-06-09 16:26:27 +00:00
|
|
|
|
using Content.Server._White.Wizard.Teleport;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
using Content.Server.Abilities.Mime;
|
|
|
|
|
|
using Content.Server.Administration.Commands;
|
|
|
|
|
|
using Content.Server.Atmos.Components;
|
|
|
|
|
|
using Content.Server.Atmos.EntitySystems;
|
|
|
|
|
|
using Content.Server.Chat.Systems;
|
|
|
|
|
|
using Content.Server.Emp;
|
2024-06-09 16:26:27 +00:00
|
|
|
|
using Content.Server.EUI;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
using Content.Server.Lightning;
|
|
|
|
|
|
using Content.Server.Magic;
|
2024-06-18 14:55:21 +00:00
|
|
|
|
using Content.Server.Mind;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
using Content.Server.Singularity.EntitySystems;
|
2024-06-08 13:01:49 +00:00
|
|
|
|
using Content.Server.Standing;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
using Content.Server.Weapons.Ranged.Systems;
|
2024-07-24 02:19:13 +03:00
|
|
|
|
using Content.Shared._White.Antag;
|
2024-06-09 16:26:27 +00:00
|
|
|
|
using Content.Shared._White.BetrayalDagger;
|
2024-06-18 14:55:21 +00:00
|
|
|
|
using Content.Shared._White.Cult.Components;
|
2024-06-09 16:26:27 +00:00
|
|
|
|
using Content.Shared._White.Events;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
using Content.Shared._White.Wizard;
|
|
|
|
|
|
using Content.Shared._White.Wizard.Magic;
|
|
|
|
|
|
using Content.Shared.Actions;
|
2024-06-18 14:55:21 +00:00
|
|
|
|
using Content.Shared.Borer;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
using Content.Shared.Cluwne;
|
|
|
|
|
|
using Content.Shared.Coordinates.Helpers;
|
2024-07-14 12:27:20 +00:00
|
|
|
|
using Content.Shared.Damage;
|
|
|
|
|
|
using Content.Shared.Damage.Prototypes;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
using Content.Shared.Hands.Components;
|
|
|
|
|
|
using Content.Shared.Hands.EntitySystems;
|
|
|
|
|
|
using Content.Shared.Humanoid;
|
|
|
|
|
|
using Content.Shared.Interaction.Components;
|
|
|
|
|
|
using Content.Shared.Inventory;
|
|
|
|
|
|
using Content.Shared.Inventory.VirtualItem;
|
|
|
|
|
|
using Content.Shared.Item;
|
|
|
|
|
|
using Content.Shared.Magic;
|
|
|
|
|
|
using Content.Shared.Maps;
|
2024-06-20 16:24:10 +00:00
|
|
|
|
using Content.Shared.Mobs;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
using Content.Shared.Mobs.Components;
|
|
|
|
|
|
using Content.Shared.Physics;
|
|
|
|
|
|
using Content.Shared.Popups;
|
2024-06-18 14:55:21 +00:00
|
|
|
|
using Content.Shared.Revolutionary.Components;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
using Content.Shared.StatusEffect;
|
|
|
|
|
|
using Content.Shared.Throwing;
|
|
|
|
|
|
using Robust.Shared.Audio.Systems;
|
|
|
|
|
|
using Robust.Shared.Map;
|
|
|
|
|
|
using Robust.Shared.Physics.Components;
|
2024-06-09 16:26:27 +00:00
|
|
|
|
using Robust.Shared.Player;
|
2024-07-14 12:27:20 +00:00
|
|
|
|
using Robust.Shared.Prototypes;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
using Robust.Shared.Random;
|
|
|
|
|
|
|
|
|
|
|
|
namespace Content.Server._White.Wizard.Magic;
|
|
|
|
|
|
|
|
|
|
|
|
public sealed class WizardSpellsSystem : EntitySystem
|
|
|
|
|
|
{
|
|
|
|
|
|
#region Dependencies
|
|
|
|
|
|
|
|
|
|
|
|
[Dependency] private readonly IMapManager _mapManager = default!;
|
|
|
|
|
|
[Dependency] private readonly IRobustRandom _random = default!;
|
2024-07-14 12:27:20 +00:00
|
|
|
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
|
|
|
|
|
[Dependency] private readonly GunSystem _gunSystem = default!;
|
|
|
|
|
|
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
|
|
|
|
|
|
[Dependency] private readonly ChatSystem _chat = default!;
|
|
|
|
|
|
[Dependency] private readonly LightningSystem _lightning = default!;
|
|
|
|
|
|
[Dependency] private readonly MagicSystem _magicSystem = default!;
|
|
|
|
|
|
[Dependency] private readonly GravityWellSystem _gravityWell = default!;
|
|
|
|
|
|
[Dependency] private readonly FlammableSystem _flammableSystem = default!;
|
|
|
|
|
|
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
|
|
|
|
|
|
[Dependency] private readonly ThrowingSystem _throwingSystem = default!;
|
|
|
|
|
|
[Dependency] private readonly TurfSystem _turf = default!;
|
|
|
|
|
|
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
|
|
|
|
|
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
|
|
|
|
|
|
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
|
|
|
|
|
[Dependency] private readonly InventorySystem _inventory = default!;
|
|
|
|
|
|
[Dependency] private readonly EmpSystem _empSystem = default!;
|
2024-06-07 16:02:23 +00:00
|
|
|
|
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
2024-06-08 13:01:49 +00:00
|
|
|
|
[Dependency] private readonly StandingStateSystem _standing = default!;
|
2024-06-09 16:26:27 +00:00
|
|
|
|
[Dependency] private readonly TelefragSystem _telefrag = default!;
|
|
|
|
|
|
[Dependency] private readonly EuiManager _euiManager = default!;
|
2024-06-18 14:55:21 +00:00
|
|
|
|
[Dependency] private readonly MindSystem _mindSystem = default!;
|
|
|
|
|
|
[Dependency] private readonly ActionContainerSystem _actionContainer = default!;
|
2024-07-01 11:23:51 +00:00
|
|
|
|
[Dependency] private readonly ChargingSystem _charging = default!;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
public override void Initialize()
|
|
|
|
|
|
{
|
|
|
|
|
|
base.Initialize();
|
|
|
|
|
|
|
2024-06-22 12:55:50 +00:00
|
|
|
|
SubscribeLocalEvent<ArcaneBarrageSpellEvent>(OnArcaneBarrage);
|
2024-06-20 16:24:10 +00:00
|
|
|
|
SubscribeLocalEvent<StopTimeSpellEvent>(OnTimeStop);
|
2024-06-18 14:55:21 +00:00
|
|
|
|
SubscribeLocalEvent<MindswapSpellEvent>(OnMindswapSpell);
|
2024-06-09 16:26:27 +00:00
|
|
|
|
SubscribeLocalEvent<TeleportSpellEvent>(OnTeleportSpell);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
SubscribeLocalEvent<InstantRecallSpellEvent>(OnInstantRecallSpell);
|
|
|
|
|
|
SubscribeLocalEvent<MimeTouchSpellEvent>(OnMimeTouchSpell);
|
|
|
|
|
|
SubscribeLocalEvent<BananaTouchSpellEvent>(OnBananaTouchSpell);
|
|
|
|
|
|
SubscribeLocalEvent<CluwneCurseSpellEvent>(OnCluwneCurseSpell);
|
|
|
|
|
|
SubscribeLocalEvent<EmpSpellEvent>(OnEmpSpell);
|
|
|
|
|
|
SubscribeLocalEvent<EtherealJauntSpellEvent>(OnJauntSpell);
|
|
|
|
|
|
SubscribeLocalEvent<BlinkSpellEvent>(OnBlinkSpell);
|
|
|
|
|
|
SubscribeLocalEvent<ForceWallSpellEvent>(OnForcewallSpell);
|
|
|
|
|
|
SubscribeLocalEvent<CardsSpellEvent>(OnCardsSpell);
|
|
|
|
|
|
SubscribeLocalEvent<FireballSpellEvent>(OnFireballSpell);
|
|
|
|
|
|
SubscribeLocalEvent<ForceSpellEvent>(OnForceSpell);
|
|
|
|
|
|
SubscribeLocalEvent<ArcSpellEvent>(OnArcSpell);
|
|
|
|
|
|
|
|
|
|
|
|
SubscribeLocalEvent<MagicComponent, BeforeCastSpellEvent>(OnBeforeCastSpell);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-22 12:55:50 +00:00
|
|
|
|
#region Arcane Barrage
|
|
|
|
|
|
|
|
|
|
|
|
private void OnArcaneBarrage(ArcaneBarrageSpellEvent msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!CanCast(msg))
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
var uid = msg.Performer;
|
|
|
|
|
|
|
|
|
|
|
|
var entity = Spawn(msg.Prototype, Transform(uid).Coordinates);
|
|
|
|
|
|
if (!_handsSystem.TryPickupAnyHand(uid, entity))
|
|
|
|
|
|
{
|
|
|
|
|
|
_popupSystem.PopupEntity(Loc.GetString("arcane-barrage-no-empty-hand"), uid, uid);
|
|
|
|
|
|
QueueDel(entity);
|
|
|
|
|
|
_actions.SetCooldown(msg.Action, TimeSpan.FromSeconds(1));
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-01 11:23:51 +00:00
|
|
|
|
Cast(msg);
|
2024-06-22 12:55:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2024-06-20 16:24:10 +00:00
|
|
|
|
#region Timestop
|
|
|
|
|
|
|
|
|
|
|
|
private void OnTimeStop(StopTimeSpellEvent msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!CanCast(msg))
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
var ent = Spawn(msg.Prototype, Transform(msg.Performer).Coordinates);
|
|
|
|
|
|
_transformSystem.AttachToGridOrMap(ent);
|
|
|
|
|
|
|
|
|
|
|
|
var comp = EnsureComp<PreventCollideComponent>(ent);
|
|
|
|
|
|
comp.Uid = msg.Performer;
|
|
|
|
|
|
|
2024-07-01 11:23:51 +00:00
|
|
|
|
Cast(msg);
|
2024-06-20 16:24:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2024-06-18 14:55:21 +00:00
|
|
|
|
#region Mindswap
|
|
|
|
|
|
|
|
|
|
|
|
private void OnMindswapSpell(MindswapSpellEvent msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!CanCast(msg))
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
var target = msg.Target;
|
|
|
|
|
|
var uid = msg.Performer;
|
|
|
|
|
|
|
2024-06-20 16:24:10 +00:00
|
|
|
|
if (!TryComp(target, out MobStateComponent? mobState) || mobState.CurrentState != MobState.Alive)
|
2024-06-18 14:55:21 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (TryComp(target, out InfestedBorerComponent? borer) && borer.ControllingBrain)
|
|
|
|
|
|
{
|
2024-06-20 16:24:10 +00:00
|
|
|
|
_popupSystem.PopupEntity(Loc.GetString("mindswap-borer-failed"), uid, uid, PopupType.MediumCaution);
|
2024-06-18 14:55:21 +00:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-28 16:54:32 +00:00
|
|
|
|
if (HasComp<CultistComponent>(target))
|
|
|
|
|
|
{
|
|
|
|
|
|
_popupSystem.PopupEntity(Loc.GetString("mindswap-cultist-failed"), uid, uid, PopupType.MediumCaution);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-18 14:55:21 +00:00
|
|
|
|
var userHasMind = _mindSystem.TryGetMind(uid, out var mindId, out var mind);
|
|
|
|
|
|
var targetHasMind = _mindSystem.TryGetMind(target, out var targetMindId, out var targetMind);
|
|
|
|
|
|
|
|
|
|
|
|
if (!userHasMind)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2024-07-19 12:52:40 +00:00
|
|
|
|
SwapComponent<WizardComponent>(uid, target);
|
|
|
|
|
|
SwapComponent<RevolutionaryComponent>(uid, target);
|
|
|
|
|
|
SwapComponent<HeadRevolutionaryComponent>(uid, target);
|
2024-07-24 02:19:13 +03:00
|
|
|
|
SwapComponent<GlobalAntagonistComponent>(uid, target);
|
2024-07-19 12:52:40 +00:00
|
|
|
|
|
2024-06-18 14:55:21 +00:00
|
|
|
|
_mindSystem.TransferTo(mindId, target, mind: mind);
|
|
|
|
|
|
|
|
|
|
|
|
if (targetHasMind)
|
|
|
|
|
|
{
|
|
|
|
|
|
_mindSystem.TransferTo(targetMindId, uid, mind: targetMind);
|
2024-06-20 16:24:10 +00:00
|
|
|
|
_popupSystem.PopupEntity(Loc.GetString("mindswap-success"), uid, uid, PopupType.LargeCaution);
|
2024-06-18 14:55:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TransferAllMagicActions(uid, target);
|
|
|
|
|
|
|
2024-07-24 02:19:13 +03:00
|
|
|
|
// This is bad, but EnsureComp cant copy variables
|
|
|
|
|
|
if (TryComp<GlobalAntagonistComponent>(target, out var globalAntagonistComponent))
|
|
|
|
|
|
globalAntagonistComponent.AntagonistPrototype = "globalAntagonistWizard";
|
|
|
|
|
|
|
2024-06-18 14:55:21 +00:00
|
|
|
|
_standing.TryLieDown(uid);
|
|
|
|
|
|
_standing.TryLieDown(target);
|
|
|
|
|
|
|
2024-07-01 11:23:51 +00:00
|
|
|
|
Cast(msg);
|
2024-06-18 14:55:21 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2024-06-09 16:26:27 +00:00
|
|
|
|
#region Teleport
|
|
|
|
|
|
|
|
|
|
|
|
private void OnTeleportSpell(TeleportSpellEvent msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!CanCast(msg))
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (!TryComp(msg.Performer, out ActorComponent? actor))
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2024-06-11 20:07:47 +00:00
|
|
|
|
var eui = new WizardTeleportSpellEui(msg.Performer);
|
2024-06-09 16:26:27 +00:00
|
|
|
|
_euiManager.OpenEui(eui, actor.PlayerSession);
|
|
|
|
|
|
eui.StateDirty();
|
|
|
|
|
|
|
2024-07-01 11:23:51 +00:00
|
|
|
|
Cast(msg, false);
|
2024-06-09 16:26:27 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2024-03-07 16:01:54 +00:00
|
|
|
|
#region Instant Recall
|
|
|
|
|
|
|
|
|
|
|
|
private void OnInstantRecallSpell(InstantRecallSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
if (!CanCast(msg))
|
2024-03-07 16:01:54 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (!TryComp<HandsComponent>(msg.Performer, out var handsComponent))
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (!TryComp<InstantRecallComponent>(msg.Action, out var recallComponent))
|
|
|
|
|
|
{
|
|
|
|
|
|
_popupSystem.PopupEntity("Что-то поломалось!", msg.Performer, msg.Performer);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (handsComponent.ActiveHandEntity != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (HasComp<VirtualItemComponent>(handsComponent.ActiveHandEntity.Value))
|
|
|
|
|
|
{
|
|
|
|
|
|
_popupSystem.PopupEntity("Не могу работать с этим!", msg.Performer, msg.Performer);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
recallComponent.Item = handsComponent.ActiveHandEntity.Value;
|
2024-06-08 13:01:49 +00:00
|
|
|
|
_popupSystem.PopupEntity($"Сопряжено с {MetaData(handsComponent.ActiveHandEntity.Value).EntityName}",
|
|
|
|
|
|
msg.Performer, msg.Performer);
|
2024-06-19 05:47:35 +03:00
|
|
|
|
_audio.PlayPvs(recallComponent.LinkSound, msg.Performer);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-08 13:01:49 +00:00
|
|
|
|
if (handsComponent.ActiveHandEntity == null && recallComponent.Item != null &&
|
|
|
|
|
|
Exists(recallComponent.Item.Value))
|
2024-03-07 16:01:54 +00:00
|
|
|
|
{
|
|
|
|
|
|
var coordsItem = Transform(recallComponent.Item.Value).Coordinates;
|
|
|
|
|
|
var coordsPerformer = Transform(msg.Performer).Coordinates;
|
|
|
|
|
|
|
2024-06-19 05:47:35 +03:00
|
|
|
|
Spawn("EffectMagicDisappearance", coordsItem);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
|
|
|
|
|
|
_transformSystem.SetCoordinates(recallComponent.Item.Value, coordsPerformer);
|
|
|
|
|
|
_transformSystem.AttachToGridOrMap(recallComponent.Item.Value);
|
|
|
|
|
|
|
|
|
|
|
|
_handsSystem.TryForcePickupAnyHand(msg.Performer, recallComponent.Item.Value);
|
2024-06-19 05:47:35 +03:00
|
|
|
|
_audio.PlayPvs(recallComponent.RecallSound, msg.Performer);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
|
2024-07-01 11:23:51 +00:00
|
|
|
|
Cast(msg);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_popupSystem.PopupEntity("Нет привязки.", msg.Performer, msg.Performer);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Mime Touch
|
|
|
|
|
|
|
|
|
|
|
|
private void OnMimeTouchSpell(MimeTouchSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
if (!CanCast(msg))
|
2024-03-07 16:01:54 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (!HasComp<HumanoidAppearanceComponent>(msg.Target))
|
|
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
_popupSystem.PopupEntity("Работает только на людях!", msg.Performer, msg.Performer);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SetOutfitCommand.SetOutfit(msg.Target, "MimeGear", EntityManager);
|
2024-06-07 16:02:23 +00:00
|
|
|
|
var powers = EnsureComp<MimePowersComponent>(msg.Target);
|
|
|
|
|
|
powers.CanBreakVow = false;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
|
|
|
|
|
|
Spawn("AdminInstantEffectSmoke3", Transform(msg.Target).Coordinates);
|
|
|
|
|
|
|
2024-07-01 11:23:51 +00:00
|
|
|
|
Cast(msg);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Banana Touch
|
|
|
|
|
|
|
|
|
|
|
|
private void OnBananaTouchSpell(BananaTouchSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
if (!CanCast(msg))
|
2024-03-07 16:01:54 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (!HasComp<HumanoidAppearanceComponent>(msg.Target))
|
|
|
|
|
|
{
|
|
|
|
|
|
_popupSystem.PopupEntity("Работает только на людях!", msg.Performer, msg.Performer);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SetOutfitCommand.SetOutfit(msg.Target, "ClownGear", EntityManager);
|
2024-07-14 12:27:20 +00:00
|
|
|
|
var clumsy = EnsureComp<ClumsyComponent>(msg.Target);
|
|
|
|
|
|
clumsy.ClumsyDamage = new DamageSpecifier(_prototypeManager.Index<DamageGroupPrototype>("Brute"), 12);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
|
|
|
|
|
|
Spawn("AdminInstantEffectSmoke3", Transform(msg.Target).Coordinates);
|
|
|
|
|
|
|
2024-07-01 11:23:51 +00:00
|
|
|
|
Cast(msg);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Cluwne Curse
|
|
|
|
|
|
|
|
|
|
|
|
private void OnCluwneCurseSpell(CluwneCurseSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
if (!CanCast(msg))
|
2024-03-07 16:01:54 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (!HasComp<HumanoidAppearanceComponent>(msg.Target))
|
|
|
|
|
|
{
|
|
|
|
|
|
_popupSystem.PopupEntity("Работает только на людях!", msg.Performer, msg.Performer);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-08 13:01:49 +00:00
|
|
|
|
EnsureComp<CluwneComponent>(msg.Target);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
|
|
|
|
|
|
Spawn("AdminInstantEffectSmoke3", Transform(msg.Target).Coordinates);
|
|
|
|
|
|
|
2024-07-01 11:23:51 +00:00
|
|
|
|
Cast(msg);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region EMP
|
|
|
|
|
|
|
|
|
|
|
|
private void OnEmpSpell(EmpSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
if (!CanCast(msg))
|
2024-03-07 16:01:54 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
var coords = _transformSystem.ToMapCoordinates(Transform(msg.Performer).Coordinates);
|
|
|
|
|
|
|
|
|
|
|
|
_empSystem.EmpPulse(coords, 15, 1000000, 60f);
|
|
|
|
|
|
|
2024-07-01 11:23:51 +00:00
|
|
|
|
Cast(msg);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Ethereal Jaunt
|
|
|
|
|
|
|
|
|
|
|
|
private void OnJauntSpell(EtherealJauntSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
if (!CanCast(msg))
|
2024-03-07 16:01:54 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (_statusEffectsSystem.HasStatusEffect(msg.Performer, "Incorporeal"))
|
|
|
|
|
|
{
|
|
|
|
|
|
_popupSystem.PopupEntity("Вы уже в потустороннем мире", msg.Performer, msg.Performer);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Spawn("AdminInstantEffectSmoke10", Transform(msg.Performer).Coordinates);
|
|
|
|
|
|
|
2024-06-08 13:01:49 +00:00
|
|
|
|
_statusEffectsSystem.TryAddStatusEffect<IncorporealComponent>(msg.Performer, "Incorporeal",
|
|
|
|
|
|
TimeSpan.FromSeconds(10), false);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
|
2024-07-01 11:23:51 +00:00
|
|
|
|
Cast(msg);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Blink
|
|
|
|
|
|
|
|
|
|
|
|
private void OnBlinkSpell(BlinkSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
if (!CanCast(msg))
|
2024-03-07 16:01:54 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
var transform = Transform(msg.Performer);
|
|
|
|
|
|
|
|
|
|
|
|
var oldCoords = transform.Coordinates;
|
|
|
|
|
|
|
|
|
|
|
|
EntityCoordinates coords = default;
|
|
|
|
|
|
var foundTeleportPos = false;
|
|
|
|
|
|
var attempts = 10;
|
|
|
|
|
|
|
|
|
|
|
|
while (attempts > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
attempts--;
|
|
|
|
|
|
|
|
|
|
|
|
var random = new Random().Next(10, 20);
|
|
|
|
|
|
var offset = transform.LocalRotation.ToWorldVec().Normalized();
|
|
|
|
|
|
var direction = transform.LocalRotation.GetDir().ToVec();
|
|
|
|
|
|
var newOffset = offset + direction * random;
|
|
|
|
|
|
coords = transform.Coordinates.Offset(newOffset).SnapToGrid(EntityManager);
|
|
|
|
|
|
|
|
|
|
|
|
var tile = coords.GetTileRef();
|
|
|
|
|
|
|
|
|
|
|
|
if (tile != null && _turf.IsTileBlocked(tile.Value, CollisionGroup.AllMask))
|
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
|
|
foundTeleportPos = true;
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!foundTeleportPos)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2024-06-09 16:26:27 +00:00
|
|
|
|
_telefrag.Telefrag(coords, msg.Performer);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
_transformSystem.SetCoordinates(msg.Performer, coords);
|
|
|
|
|
|
_transformSystem.AttachToGridOrMap(msg.Performer);
|
|
|
|
|
|
|
|
|
|
|
|
_audio.PlayPvs("/Audio/White/Cult/veilin.ogg", coords);
|
|
|
|
|
|
_audio.PlayPvs("/Audio/White/Cult/veilout.ogg", oldCoords);
|
|
|
|
|
|
|
2024-06-08 13:01:49 +00:00
|
|
|
|
Spawn("AdminInstantEffectSmoke3", oldCoords);
|
|
|
|
|
|
Spawn("AdminInstantEffectSmoke3", coords);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
|
2024-07-01 11:23:51 +00:00
|
|
|
|
Cast(msg);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Forcewall
|
|
|
|
|
|
|
|
|
|
|
|
private void OnForcewallSpell(ForceWallSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
if (!CanCast(msg))
|
2024-03-07 16:01:54 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
switch (msg.ActionUseType)
|
|
|
|
|
|
{
|
|
|
|
|
|
case ActionUseType.Default:
|
|
|
|
|
|
ForcewallSpellDefault(msg);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case ActionUseType.Charge:
|
|
|
|
|
|
ForcewallSpellCharge(msg);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case ActionUseType.AltUse:
|
|
|
|
|
|
ForcewallSpellAlt(msg);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-01 11:23:51 +00:00
|
|
|
|
Cast(msg);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void ForcewallSpellDefault(ForceWallSpellEvent msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
var transform = Transform(msg.Performer);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var position in _magicSystem.GetPositionsInFront(transform))
|
|
|
|
|
|
{
|
|
|
|
|
|
var ent = Spawn(msg.Prototype, position.SnapToGrid(EntityManager, _mapManager));
|
|
|
|
|
|
|
|
|
|
|
|
var comp = EnsureComp<PreventCollideComponent>(ent);
|
|
|
|
|
|
comp.Uid = msg.Performer;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void ForcewallSpellCharge(ForceWallSpellEvent msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
var xform = Transform(msg.Performer);
|
|
|
|
|
|
|
2024-06-07 16:02:23 +00:00
|
|
|
|
var positions = GetArenaPositions(xform.Coordinates, msg.ChargeLevel);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
|
|
|
|
|
|
foreach (var position in positions)
|
|
|
|
|
|
{
|
|
|
|
|
|
var ent = Spawn(msg.Prototype, position);
|
|
|
|
|
|
|
|
|
|
|
|
var comp = EnsureComp<PreventCollideComponent>(ent);
|
|
|
|
|
|
comp.Uid = msg.Performer;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void ForcewallSpellAlt(ForceWallSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-07 16:02:23 +00:00
|
|
|
|
var positions = GetArenaPositions(msg.Target, 2);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
|
|
|
|
|
|
foreach (var direction in positions)
|
|
|
|
|
|
{
|
|
|
|
|
|
var ent = Spawn(msg.Prototype, direction);
|
|
|
|
|
|
|
|
|
|
|
|
var comp = EnsureComp<PreventCollideComponent>(ent);
|
|
|
|
|
|
comp.Uid = msg.Performer;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Cards
|
|
|
|
|
|
|
|
|
|
|
|
private void OnCardsSpell(CardsSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
if (!CanCast(msg))
|
2024-03-07 16:01:54 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
2024-06-07 16:02:23 +00:00
|
|
|
|
var result = true;
|
|
|
|
|
|
|
2024-03-07 16:01:54 +00:00
|
|
|
|
switch (msg.ActionUseType)
|
|
|
|
|
|
{
|
|
|
|
|
|
case ActionUseType.Default:
|
|
|
|
|
|
CardsSpellDefault(msg);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case ActionUseType.Charge:
|
|
|
|
|
|
CardsSpellCharge(msg);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case ActionUseType.AltUse:
|
2024-06-07 16:02:23 +00:00
|
|
|
|
result = CardsSpellAlt(msg);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-07 16:02:23 +00:00
|
|
|
|
if (!result)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2024-07-01 11:23:51 +00:00
|
|
|
|
Cast(msg);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void CardsSpellDefault(CardsSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-09 16:26:27 +00:00
|
|
|
|
TurnOffShield(msg.Performer);
|
|
|
|
|
|
|
2024-03-07 16:01:54 +00:00
|
|
|
|
var xform = Transform(msg.Performer);
|
|
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < 10; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var pos in _magicSystem.GetSpawnPositions(xform, msg.Pos))
|
|
|
|
|
|
{
|
|
|
|
|
|
var mapPos = _transformSystem.ToMapCoordinates(pos);
|
|
|
|
|
|
var spawnCoords = _mapManager.TryFindGridAt(mapPos, out var gridUid, out _)
|
|
|
|
|
|
? pos.WithEntityId(gridUid, EntityManager)
|
|
|
|
|
|
: new EntityCoordinates(_mapManager.GetMapEntityId(mapPos.MapId), mapPos.Position);
|
|
|
|
|
|
|
|
|
|
|
|
var ent = Spawn(msg.Prototype, spawnCoords);
|
|
|
|
|
|
|
2024-06-08 13:01:49 +00:00
|
|
|
|
var direction = msg.Target.ToMapPos(EntityManager, _transformSystem) -
|
|
|
|
|
|
spawnCoords.ToMapPos(EntityManager, _transformSystem);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
var randomizedDirection = direction + new Vector2(_random.Next(-2, 2), _random.Next(-2, 2));
|
|
|
|
|
|
|
|
|
|
|
|
_throwingSystem.TryThrow(ent, randomizedDirection, 60, msg.Performer);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void CardsSpellCharge(CardsSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-09 16:26:27 +00:00
|
|
|
|
TurnOffShield(msg.Performer);
|
|
|
|
|
|
|
2024-03-07 16:01:54 +00:00
|
|
|
|
var xform = Transform(msg.Performer);
|
|
|
|
|
|
|
2024-06-08 13:01:49 +00:00
|
|
|
|
var count = 10 + 10 * msg.ChargeLevel;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
var angleStep = 360f / count;
|
|
|
|
|
|
|
|
|
|
|
|
for (var i = 0; i < count; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var angle = i * angleStep;
|
|
|
|
|
|
|
2024-06-08 13:01:49 +00:00
|
|
|
|
var direction = new Vector2(MathF.Cos(MathHelper.DegreesToRadians(angle)),
|
|
|
|
|
|
MathF.Sin(MathHelper.DegreesToRadians(angle)));
|
2024-03-07 16:01:54 +00:00
|
|
|
|
|
|
|
|
|
|
foreach (var pos in _magicSystem.GetSpawnPositions(xform, msg.Pos))
|
|
|
|
|
|
{
|
|
|
|
|
|
var mapPos = _transformSystem.ToMapCoordinates(pos);
|
|
|
|
|
|
|
|
|
|
|
|
var spawnCoords = _mapManager.TryFindGridAt(mapPos, out var gridUid, out _)
|
|
|
|
|
|
? pos.WithEntityId(gridUid, EntityManager)
|
|
|
|
|
|
: new EntityCoordinates(_mapManager.GetMapEntityId(mapPos.MapId), mapPos.Position);
|
|
|
|
|
|
|
|
|
|
|
|
var ent = Spawn(msg.Prototype, spawnCoords);
|
|
|
|
|
|
|
|
|
|
|
|
_throwingSystem.TryThrow(ent, direction, 60, msg.Performer);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-07 16:02:23 +00:00
|
|
|
|
private bool CardsSpellAlt(CardsSpellEvent msg)
|
2024-03-07 16:01:54 +00:00
|
|
|
|
{
|
|
|
|
|
|
if (!HasComp<ItemComponent>(msg.TargetUid))
|
2024-06-07 16:02:23 +00:00
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
_popupSystem.PopupEntity("В карту можно превратить только предметы.", msg.Performer, msg.Performer);
|
2024-06-07 16:02:23 +00:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2024-03-07 16:01:54 +00:00
|
|
|
|
|
|
|
|
|
|
Del(msg.TargetUid);
|
|
|
|
|
|
var item = Spawn(msg.Prototype);
|
|
|
|
|
|
_handsSystem.TryPickupAnyHand(msg.Performer, item);
|
2024-06-09 16:26:27 +00:00
|
|
|
|
TurnOffShield(msg.Performer);
|
2024-06-07 16:02:23 +00:00
|
|
|
|
|
|
|
|
|
|
return true;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Fireball
|
|
|
|
|
|
|
|
|
|
|
|
private void OnFireballSpell(FireballSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
if (!CanCast(msg))
|
2024-03-07 16:01:54 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
2024-06-07 16:02:23 +00:00
|
|
|
|
var result = true;
|
|
|
|
|
|
|
2024-03-07 16:01:54 +00:00
|
|
|
|
switch (msg.ActionUseType)
|
|
|
|
|
|
{
|
|
|
|
|
|
case ActionUseType.Default:
|
|
|
|
|
|
FireballSpellDefault(msg);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case ActionUseType.Charge:
|
|
|
|
|
|
FireballSpellCharge(msg);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case ActionUseType.AltUse:
|
2024-06-07 16:02:23 +00:00
|
|
|
|
result = FireballSpellAlt(msg);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-07 16:02:23 +00:00
|
|
|
|
if (!result)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2024-07-01 11:23:51 +00:00
|
|
|
|
Cast(msg);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void FireballSpellDefault(FireballSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-09 16:26:27 +00:00
|
|
|
|
TurnOffShield(msg.Performer);
|
|
|
|
|
|
|
2024-03-07 16:01:54 +00:00
|
|
|
|
var xform = Transform(msg.Performer);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var pos in _magicSystem.GetSpawnPositions(xform, msg.Pos))
|
|
|
|
|
|
{
|
|
|
|
|
|
var mapPos = _transformSystem.ToMapCoordinates(pos);
|
|
|
|
|
|
var spawnCoords = _mapManager.TryFindGridAt(mapPos, out var gridUid, out var grid)
|
|
|
|
|
|
? pos.WithEntityId(gridUid, EntityManager)
|
|
|
|
|
|
: new EntityCoordinates(_mapManager.GetMapEntityId(mapPos.MapId), mapPos.Position);
|
|
|
|
|
|
|
|
|
|
|
|
var userVelocity = Vector2.Zero;
|
|
|
|
|
|
|
|
|
|
|
|
if (grid != null && TryComp(gridUid, out PhysicsComponent? physics))
|
|
|
|
|
|
userVelocity = physics.LinearVelocity;
|
|
|
|
|
|
|
|
|
|
|
|
var ent = Spawn(msg.Prototype, spawnCoords);
|
2024-06-08 13:01:49 +00:00
|
|
|
|
var direction = msg.Target.ToMapPos(EntityManager, _transformSystem) -
|
|
|
|
|
|
spawnCoords.ToMapPos(EntityManager, _transformSystem);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
_gunSystem.ShootProjectile(ent, direction, userVelocity, msg.Performer, msg.Performer);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void FireballSpellCharge(FireballSpellEvent msg)
|
|
|
|
|
|
{
|
|
|
|
|
|
var coords = Transform(msg.Performer).Coordinates;
|
|
|
|
|
|
|
|
|
|
|
|
var targets = _lookup.GetEntitiesInRange<FlammableComponent>(coords, 2 * msg.ChargeLevel);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var target in targets.Where(target => target.Owner != msg.Performer))
|
|
|
|
|
|
{
|
2024-06-07 16:02:23 +00:00
|
|
|
|
target.Comp.FireStacks += 2 + msg.ChargeLevel * 2;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
_flammableSystem.Ignite(target, msg.Performer);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-07 16:02:23 +00:00
|
|
|
|
private bool FireballSpellAlt(FireballSpellEvent msg)
|
2024-03-07 16:01:54 +00:00
|
|
|
|
{
|
|
|
|
|
|
if (!TryComp<FlammableComponent>(msg.TargetUid, out var flammableComponent))
|
2024-06-07 16:02:23 +00:00
|
|
|
|
{
|
|
|
|
|
|
_popupSystem.PopupEntity("Это нельзя поджечь!", msg.Performer, msg.Performer);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2024-03-07 16:01:54 +00:00
|
|
|
|
|
|
|
|
|
|
flammableComponent.FireStacks += 4;
|
|
|
|
|
|
|
|
|
|
|
|
_flammableSystem.Ignite(msg.TargetUid, msg.Performer);
|
|
|
|
|
|
|
|
|
|
|
|
EnsureComp<AmaterasuComponent>(msg.TargetUid);
|
2024-06-07 16:02:23 +00:00
|
|
|
|
|
|
|
|
|
|
return true;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Force
|
|
|
|
|
|
|
|
|
|
|
|
private void OnForceSpell(ForceSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
if (!CanCast(msg))
|
2024-03-07 16:01:54 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
2024-06-08 13:01:49 +00:00
|
|
|
|
var result = true;
|
|
|
|
|
|
|
2024-03-07 16:01:54 +00:00
|
|
|
|
switch (msg.ActionUseType)
|
|
|
|
|
|
{
|
|
|
|
|
|
case ActionUseType.Default:
|
|
|
|
|
|
ForceSpellDefault(msg);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case ActionUseType.Charge:
|
|
|
|
|
|
ForceSpellCharge(msg);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case ActionUseType.AltUse:
|
2024-06-08 13:01:49 +00:00
|
|
|
|
result = ForceSpellAlt(msg);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-08 13:01:49 +00:00
|
|
|
|
if (!result)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2024-07-01 11:23:51 +00:00
|
|
|
|
Cast(msg);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-08 13:01:49 +00:00
|
|
|
|
private bool ForceSpellAlt(ForceSpellEvent msg)
|
2024-03-07 16:01:54 +00:00
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
if (!HasComp<TransformComponent>(msg.TargetUid) || !HasComp<PhysicsComponent>(msg.TargetUid))
|
|
|
|
|
|
{
|
|
|
|
|
|
_popupSystem.PopupEntity("Невозможно это притянуть!", msg.Performer, msg.Performer);
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_throwingSystem.TryThrow(msg.TargetUid, Transform(msg.Performer).Coordinates, 5f);
|
|
|
|
|
|
_standing.TryLieDown(msg.TargetUid);
|
|
|
|
|
|
|
|
|
|
|
|
return true;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void ForceSpellCharge(ForceSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
_gravityWell.GravPulse(msg.Performer, 15, 0, -80 * msg.ChargeLevel, -2 * msg.ChargeLevel, null, msg.ChargeLevel,
|
|
|
|
|
|
new() {msg.Performer});
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-08 13:01:49 +00:00
|
|
|
|
private void ForceSpellDefault(ForceSpellEvent msg)
|
2024-03-07 16:01:54 +00:00
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
_gravityWell.GravPulse(msg.Target, 10, 0, 200, 10, 2f, new() {msg.Performer});
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Arc
|
|
|
|
|
|
|
|
|
|
|
|
private void OnArcSpell(ArcSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
if (!CanCast(msg))
|
2024-03-07 16:01:54 +00:00
|
|
|
|
return;
|
|
|
|
|
|
|
2024-06-07 16:02:23 +00:00
|
|
|
|
var result = true;
|
|
|
|
|
|
|
2024-03-07 16:01:54 +00:00
|
|
|
|
switch (msg.ActionUseType)
|
|
|
|
|
|
{
|
|
|
|
|
|
case ActionUseType.Default:
|
2024-06-07 16:02:23 +00:00
|
|
|
|
result = ArcSpellDefault(msg);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
break;
|
|
|
|
|
|
case ActionUseType.Charge:
|
|
|
|
|
|
ArcSpellCharge(msg);
|
|
|
|
|
|
break;
|
|
|
|
|
|
case ActionUseType.AltUse:
|
|
|
|
|
|
ArcSpellAlt(msg);
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-07 16:02:23 +00:00
|
|
|
|
if (!result)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2024-07-01 11:23:51 +00:00
|
|
|
|
Cast(msg);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-07 16:02:23 +00:00
|
|
|
|
private bool ArcSpellDefault(ArcSpellEvent msg)
|
2024-03-07 16:01:54 +00:00
|
|
|
|
{
|
|
|
|
|
|
const int possibleEntitiesCount = 2;
|
|
|
|
|
|
|
|
|
|
|
|
var entitiesInRange = _lookup.GetEntitiesInRange(msg.Target, 1);
|
|
|
|
|
|
var entitiesToHit = entitiesInRange.Where(HasComp<MobStateComponent>).Take(possibleEntitiesCount);
|
|
|
|
|
|
|
2024-06-07 16:02:23 +00:00
|
|
|
|
var entityUids = entitiesToHit.ToList();
|
|
|
|
|
|
foreach (var entity in entityUids)
|
2024-03-07 16:01:54 +00:00
|
|
|
|
{
|
2024-06-08 13:01:49 +00:00
|
|
|
|
_lightning.ShootLightning(msg.Performer, entity, "WizardLightning", true, msg.Performer);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
2024-06-07 16:02:23 +00:00
|
|
|
|
|
|
|
|
|
|
return entityUids.Count != 0;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void ArcSpellCharge(ArcSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-09 16:26:27 +00:00
|
|
|
|
_lightning.ShootRandomLightnings(msg.Performer, 1.5f * msg.ChargeLevel, msg.ChargeLevel * 2, "WizardLightning", 2,
|
2024-06-08 13:01:49 +00:00
|
|
|
|
caster: msg.Performer);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void ArcSpellAlt(ArcSpellEvent msg)
|
|
|
|
|
|
{
|
2024-06-09 16:26:27 +00:00
|
|
|
|
TurnOffShield(msg.Performer);
|
|
|
|
|
|
|
2024-03-07 16:01:54 +00:00
|
|
|
|
var xform = Transform(msg.Performer);
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var pos in _magicSystem.GetSpawnPositions(xform, msg.Pos))
|
|
|
|
|
|
{
|
|
|
|
|
|
var mapPos = _transformSystem.ToMapCoordinates(pos);
|
|
|
|
|
|
var spawnCoords = _mapManager.TryFindGridAt(mapPos, out var gridUid, out var grid)
|
|
|
|
|
|
? pos.WithEntityId(gridUid, EntityManager)
|
|
|
|
|
|
: new EntityCoordinates(_mapManager.GetMapEntityId(mapPos.MapId), mapPos.Position);
|
|
|
|
|
|
|
|
|
|
|
|
var userVelocity = Vector2.Zero;
|
|
|
|
|
|
|
|
|
|
|
|
if (grid != null && TryComp(gridUid, out PhysicsComponent? physics))
|
|
|
|
|
|
userVelocity = physics.LinearVelocity;
|
|
|
|
|
|
|
|
|
|
|
|
var ent = Spawn(msg.Prototype, spawnCoords);
|
2024-06-22 12:55:50 +00:00
|
|
|
|
EnsureComp<TeslaProjectileComponent>(ent).Caster = msg.Performer;
|
2024-06-08 13:01:49 +00:00
|
|
|
|
var direction = msg.Target.ToMapPos(EntityManager, _transformSystem) -
|
|
|
|
|
|
spawnCoords.ToMapPos(EntityManager, _transformSystem);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
_gunSystem.ShootProjectile(ent, direction, userVelocity, msg.Performer, msg.Performer);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region Helpers
|
|
|
|
|
|
|
2024-06-09 16:26:27 +00:00
|
|
|
|
private void TurnOffShield(EntityUid uid)
|
|
|
|
|
|
{
|
|
|
|
|
|
RaiseLocalEvent(uid, new EnergyDomeClothesTurnOffEvent());
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-01 11:23:51 +00:00
|
|
|
|
public void Cast(BaseActionEvent msg, bool removeAllCharges = true)
|
|
|
|
|
|
{
|
|
|
|
|
|
SetCooldown(msg.Action, msg.ActionUseType);
|
|
|
|
|
|
msg.Handled = true;
|
|
|
|
|
|
Speak(msg);
|
|
|
|
|
|
if (!removeAllCharges)
|
|
|
|
|
|
return;
|
|
|
|
|
|
_charging.RemoveAllCharges(msg.Performer);
|
|
|
|
|
|
_charging.StopAllSounds(msg.Performer);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-10 10:57:32 +00:00
|
|
|
|
public bool CanCast(BaseActionEvent msg)
|
2024-06-08 13:01:49 +00:00
|
|
|
|
{
|
|
|
|
|
|
return !msg.Handled && CheckRequirements(msg.Action, msg.Performer) &&
|
|
|
|
|
|
!_statusEffectsSystem.HasStatusEffect(msg.Performer, "Incorporeal");
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-28 16:54:32 +00:00
|
|
|
|
public void Speak(BaseActionEvent args, InGameICChatType type = InGameICChatType.Speak)
|
2024-03-07 16:01:54 +00:00
|
|
|
|
{
|
|
|
|
|
|
if (args is not ISpeakSpell speak || string.IsNullOrWhiteSpace(speak.Speech))
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2024-07-28 16:54:32 +00:00
|
|
|
|
_chat.TrySendInGameICMessage(args.Performer, Loc.GetString(speak.Speech), type, false);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-07 16:02:23 +00:00
|
|
|
|
private void SetCooldown(EntityUid action, ActionUseType useType)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!TryComp(action, out VariableUseDelayComponent? variableUseDelayComponent))
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
var cooldown = useType switch
|
|
|
|
|
|
{
|
|
|
|
|
|
ActionUseType.Default => variableUseDelayComponent.UseDelay,
|
|
|
|
|
|
ActionUseType.AltUse => variableUseDelayComponent.AltUseDelay,
|
|
|
|
|
|
ActionUseType.Charge => variableUseDelayComponent.ChargeUseDelay,
|
|
|
|
|
|
_ => TimeSpan.FromSeconds(60)
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
_actions.SetUseDelay(action, cooldown);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private List<EntityCoordinates> GetArenaPositions(EntityCoordinates coords, int arenaSize)
|
2024-03-07 16:01:54 +00:00
|
|
|
|
{
|
|
|
|
|
|
var positions = new List<EntityCoordinates>();
|
|
|
|
|
|
|
|
|
|
|
|
arenaSize--;
|
|
|
|
|
|
|
|
|
|
|
|
for (var i = -arenaSize; i <= arenaSize; i++)
|
|
|
|
|
|
{
|
|
|
|
|
|
for (var j = -arenaSize; j <= arenaSize; j++)
|
|
|
|
|
|
{
|
|
|
|
|
|
var position = new Vector2(i, j);
|
2024-06-07 16:02:23 +00:00
|
|
|
|
var coordinates = coords.Offset(position);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
positions.Add(coordinates);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return positions;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool CheckRequirements(EntityUid spell, EntityUid performer)
|
|
|
|
|
|
{
|
|
|
|
|
|
var ev = new BeforeCastSpellEvent(performer);
|
|
|
|
|
|
RaiseLocalEvent(spell, ref ev);
|
|
|
|
|
|
return !ev.Cancelled;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void OnBeforeCastSpell(Entity<MagicComponent> ent, ref BeforeCastSpellEvent args)
|
|
|
|
|
|
{
|
|
|
|
|
|
var comp = ent.Comp;
|
2024-06-18 14:55:21 +00:00
|
|
|
|
|
|
|
|
|
|
if (!comp.RequiresClothes)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
2024-03-07 16:01:54 +00:00
|
|
|
|
var hasReqs = false;
|
|
|
|
|
|
|
2024-06-18 14:55:21 +00:00
|
|
|
|
var enumerator = _inventory.GetSlotEnumerator(args.Performer, SlotFlags.OUTERCLOTHING | SlotFlags.HEAD);
|
|
|
|
|
|
while (enumerator.MoveNext(out var containerSlot))
|
2024-03-07 16:01:54 +00:00
|
|
|
|
{
|
2024-06-18 14:55:21 +00:00
|
|
|
|
if (containerSlot.ContainedEntity is { } item)
|
|
|
|
|
|
hasReqs = HasComp<WizardClothesComponent>(item);
|
|
|
|
|
|
else
|
|
|
|
|
|
hasReqs = false;
|
2024-03-07 16:01:54 +00:00
|
|
|
|
|
2024-06-18 14:55:21 +00:00
|
|
|
|
if (!hasReqs)
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (hasReqs)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
args.Cancelled = true;
|
|
|
|
|
|
_popupSystem.PopupEntity(Loc.GetString("magic-component-missing-req"), args.Performer, args.Performer);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void TransferAllMagicActions(EntityUid uid1, EntityUid uid2)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!TryComp(uid1, out ActionsContainerComponent? container1) ||
|
|
|
|
|
|
!TryComp(uid2, out ActionsContainerComponent? container2))
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
var actions1 = container1.Container.ContainedEntities.Where(HasComp<MagicComponent>).ToList();
|
|
|
|
|
|
var actions2 = container2.Container.ContainedEntities.Where(HasComp<MagicComponent>).ToList();
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var act in actions1)
|
|
|
|
|
|
{
|
|
|
|
|
|
_actionContainer.TransferActionWithNewAttached(act, uid2, uid2, container: container2);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-06-18 14:55:21 +00:00
|
|
|
|
foreach (var act in actions2)
|
2024-03-07 16:01:54 +00:00
|
|
|
|
{
|
2024-06-18 14:55:21 +00:00
|
|
|
|
_actionContainer.TransferActionWithNewAttached(act, uid1, uid1, container: container1);
|
2024-03-07 16:01:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-24 02:19:13 +03:00
|
|
|
|
private void SwapComponent<T>(EntityUid uidFrom, EntityUid uidTo) where T : Component, new()
|
2024-06-20 16:24:10 +00:00
|
|
|
|
{
|
2024-07-24 02:19:13 +03:00
|
|
|
|
var hasComp = HasComp<T>(uidFrom);
|
|
|
|
|
|
var targetHasComp = HasComp<T>(uidTo);
|
2024-06-20 16:24:10 +00:00
|
|
|
|
|
|
|
|
|
|
if (hasComp == targetHasComp)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (hasComp)
|
|
|
|
|
|
{
|
2024-07-24 02:19:13 +03:00
|
|
|
|
EnsureComp<T>(uidTo);
|
|
|
|
|
|
RemComp<T>(uidFrom);
|
|
|
|
|
|
|
|
|
|
|
|
return;
|
2024-06-20 16:24:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
2024-07-24 02:19:13 +03:00
|
|
|
|
if (!targetHasComp)
|
2024-06-20 16:24:10 +00:00
|
|
|
|
{
|
2024-07-24 02:19:13 +03:00
|
|
|
|
EnsureComp<T>(uidFrom);
|
|
|
|
|
|
RemComp<T>(uidTo);
|
2024-06-20 16:24:10 +00:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2024-03-07 16:01:54 +00:00
|
|
|
|
#endregion
|
|
|
|
|
|
}
|