using System.Linq; using Content.Shared._CP14.Actions.Components; using Content.Shared._CP14.MagicEnergy.Components; using Content.Shared._CP14.MagicSpell.Events; using Content.Shared._CP14.Religion.Components; using Content.Shared._CP14.Skill.Components; using Content.Shared.Actions.Components; using Content.Shared.Actions.Events; using Content.Shared.CombatMode.Pacification; using Content.Shared.Damage.Components; using Content.Shared.Hands.Components; using Content.Shared.Mobs; using Content.Shared.Mobs.Components; using Content.Shared.Popups; using Content.Shared.Speech.Muting; using Content.Shared.SSDIndicator; namespace Content.Shared._CP14.Actions; public abstract partial class CP14SharedActionSystem { private void InitializeAttempts() { SubscribeLocalEvent(OnSomaticActionAttempt); SubscribeLocalEvent(OnVerbalActionAttempt); SubscribeLocalEvent(OnMaterialActionAttempt); SubscribeLocalEvent(OnManacostActionAttempt); SubscribeLocalEvent(OnStaminaCostActionAttempt); SubscribeLocalEvent(OnDangerousActionAttempt); SubscribeLocalEvent(OnSkillPointActionAttempt); SubscribeLocalEvent(OnActionSSDAttempt); SubscribeLocalEvent(OnTargetMobStatusRequiredValidate); SubscribeLocalEvent(OnReligionActionValidate); } /// /// Before using a spell, a mana check is made for the amount of mana to show warnings. /// private void OnManacostActionAttempt(Entity ent, ref ActionAttemptEvent args) { if (args.Cancelled) return; if (!TryComp(ent, out var action)) return; //Total mana required var requiredMana = ent.Comp.ManaCost; if (ent.Comp.CanModifyManacost) { var manaEv = new CP14CalculateManacostEvent(args.User, ent.Comp.ManaCost); RaiseLocalEvent(args.User, manaEv); if (action.Container is not null) RaiseLocalEvent(action.Container.Value, manaEv); requiredMana = manaEv.GetManacost(); } //First - trying get mana from item if (action.Container is not null && TryComp(action.Container, out var magicContainer)) requiredMana = MathF.Max(0, (float)(requiredMana - magicContainer.Energy)); if (requiredMana <= 0) return; //Second - trying get mana from performer if (!TryComp(args.User, out var playerMana)) { Popup.PopupClient(Loc.GetString("cp14-magic-spell-no-mana-component"), args.User, args.User); args.Cancelled = true; return; } if (!_magicEnergy.HasEnergy(args.User, requiredMana, playerMana, true) && _timing.IsFirstTimePredicted) Popup.PopupClient(Loc.GetString($"cp14-magic-spell-not-enough-mana-cast-warning-{_random.Next(5)}"), args.User, args.User, PopupType.SmallCaution); } private void OnStaminaCostActionAttempt(Entity ent, ref ActionAttemptEvent args) { if (!TryComp(args.User, out var staminaComp)) return; if (!staminaComp.Critical) return; Popup.PopupClient(Loc.GetString("cp14-magic-spell-stamina-not-enough"), args.User, args.User); args.Cancelled = true; } private void OnSomaticActionAttempt(Entity ent, ref ActionAttemptEvent args) { if (args.Cancelled) return; if (TryComp(args.User, out var hands)) { if (_hand.CountFreeHands((args.User, hands)) >= ent.Comp.FreeHandRequired) return; } Popup.PopupClient(Loc.GetString("cp14-magic-spell-need-somatic-component"), args.User, args.User); args.Cancelled = true; } private void OnVerbalActionAttempt(Entity ent, ref ActionAttemptEvent args) { if (!HasComp(args.User)) return; Popup.PopupClient(Loc.GetString("cp14-magic-spell-need-verbal-component"), args.User, args.User); args.Cancelled = true; } private void OnMaterialActionAttempt(Entity ent, ref ActionAttemptEvent args) { if (args.Cancelled) return; if (ent.Comp.Requirement is null) return; HashSet heldedItems = new(); foreach (var hand in _hand.EnumerateHands(args.User)) { var helded = _hand.GetHeldItem(args.User, hand); if (helded is not null) heldedItems.Add(helded.Value); } if (!ent.Comp.Requirement.CheckRequirement(EntityManager, _proto, heldedItems)) { Popup.PopupClient(Loc.GetString("cp14-magic-spell-need-material-component"), args.User, args.User); args.Cancelled = true; } } private void OnDangerousActionAttempt(Entity ent, ref ActionAttemptEvent args) { if (args.Cancelled) return; if (HasComp(args.User)) { Popup.PopupClient(Loc.GetString("cp14-magic-spell-pacified"), args.User, args.User); args.Cancelled = true; } } private void OnSkillPointActionAttempt(Entity ent, ref ActionAttemptEvent args) { if (!_proto.TryIndex(ent.Comp.SkillPoint, out var indexedSkillPoint) || ent.Comp.SkillPoint is null) return; if (!TryComp(args.User, out var skillStorage)) { Popup.PopupClient(Loc.GetString("cp14-magic-spell-skillpoint-not-enough", ("name", Loc.GetString(indexedSkillPoint.Name)), ("count", ent.Comp.Count)), args.User, args.User); args.Cancelled = true; return; } var points = skillStorage.SkillPoints; if (points.TryGetValue(ent.Comp.SkillPoint.Value, out var currentPoints)) { var freePoints = currentPoints.Max - currentPoints.Sum; if (freePoints < ent.Comp.Count) { var d = ent.Comp.Count - freePoints; Popup.PopupClient(Loc.GetString("cp14-magic-spell-skillpoint-not-enough", ("name", Loc.GetString(indexedSkillPoint.Name)), ("count", d)), args.User, args.User); args.Cancelled = true; } } } private void OnTargetMobStatusRequiredValidate(Entity ent, ref ActionValidateEvent args) { if (args.Invalid) return; var target = GetEntity(args.Input.EntityTarget); if (!TryComp(target, out var mobStateComp)) { Popup.PopupClient(Loc.GetString("cp14-magic-spell-target-not-mob"), args.User, args.User); args.Invalid = true; return; } if (!ent.Comp.AllowedStates.Contains(mobStateComp.CurrentState)) { var states = string.Join(", ", ent.Comp.AllowedStates.Select(state => state switch { MobState.Alive => Loc.GetString("cp14-magic-spell-target-mob-state-live"), MobState.Dead => Loc.GetString("cp14-magic-spell-target-mob-state-dead"), MobState.Critical => Loc.GetString("cp14-magic-spell-target-mob-state-critical") })); Popup.PopupClient(Loc.GetString("cp14-magic-spell-target-mob-state", ("state", states)), args.User, args.User); args.Invalid = true; } } private void OnActionSSDAttempt(Entity ent, ref ActionValidateEvent args) { if (args.Invalid) return; if (!TryComp(GetEntity(args.Input.EntityTarget), out var ssdIndication)) return; if (ssdIndication.IsSSD) { Popup.PopupClient(Loc.GetString("cp14-magic-spell-ssd"), args.User, args.User); args.Invalid = true; } } private void OnReligionActionValidate(Entity ent, ref ActionValidateEvent args) { if (args.Invalid) return; if (!TryComp(args.User, out var religionComp)) return; var position = GetCoordinates(args.Input.EntityCoordinatesTarget); var target = GetEntity(args.Input.EntityTarget); if (target is not null) position ??= Transform(target.Value).Coordinates; if (ent.Comp.OnlyInReligionZone) { if (position is null || !_god.InVision(position.Value, (args.User, religionComp))) { args.Invalid = true; } } if (ent.Comp.OnlyOnFollowers) { if (target is null || !TryComp(target, out var follower) || follower.Religion != religionComp.Religion) { Popup.PopupClient(Loc.GetString("cp14-magic-spell-target-god-follower"), args.User, args.User); args.Invalid = true; } } } }