using System.Linq; using System.Text; using Content.Shared._CP14.Skill.Components; using Content.Shared._CP14.Skill.Prototypes; using Content.Shared.FixedPoint; using Robust.Shared.Prototypes; namespace Content.Shared._CP14.Skill; public abstract partial class CP14SharedSkillSystem : EntitySystem { private EntityQuery _skillStorageQuery = default!; public override void Initialize() { base.Initialize(); _skillStorageQuery = GetEntityQuery(); SubscribeLocalEvent(OnMapInit); InitializeAdmin(); InitializeChecks(); } private void OnMapInit(Entity ent, ref MapInitEvent args) { //If at initialization we have any skill records, we automatically give them to this entity var free = ent.Comp.FreeLearnedSkills.ToList(); var learned = ent.Comp.LearnedSkills.ToList(); ent.Comp.FreeLearnedSkills.Clear(); ent.Comp.LearnedSkills.Clear(); foreach (var skill in free) { TryAddSkill(ent.Owner, skill, ent.Comp, true); } foreach (var skill in learned) { TryAddSkill(ent.Owner, skill, ent.Comp); } } /// /// Directly adds the skill to the player, bypassing any checks. /// public bool TryAddSkill(EntityUid target, ProtoId skill, CP14SkillStorageComponent? component = null, bool free = false) { if (!Resolve(target, ref component, false)) return false; if (component.LearnedSkills.Contains(skill)) return false; if (!_proto.TryIndex(skill, out var indexedSkill)) return false; foreach (var effect in indexedSkill.Effects) { effect.AddSkill(EntityManager, target); } if (free) component.FreeLearnedSkills.Add(skill); else component.SkillsSumExperience += indexedSkill.LearnCost; component.LearnedSkills.Add(skill); Dirty(target, component); var learnEv = new CP14SkillLearnedEvent(skill, target); RaiseLocalEvent(target, ref learnEv); return true; } /// /// Removes the skill from the player, bypassing any checks. /// public bool TryRemoveSkill(EntityUid target, ProtoId skill, CP14SkillStorageComponent? component = null) { if (!Resolve(target, ref component, false)) return false; if (!component.LearnedSkills.Remove(skill)) return false; if (!_proto.TryIndex(skill, out var indexedSkill)) return false; foreach (var effect in indexedSkill.Effects) { effect.RemoveSkill(EntityManager, target); } if (!component.FreeLearnedSkills.Remove(skill)) component.SkillsSumExperience -= indexedSkill.LearnCost; Dirty(target, component); return true; } /// /// Checks if the player has the skill. /// public bool HaveSkill(EntityUid target, ProtoId skill, CP14SkillStorageComponent? component = null) { if (!Resolve(target, ref component, false)) return false; return component.LearnedSkills.Contains(skill); } public bool HaveFreeSkill(EntityUid target, ProtoId skill, CP14SkillStorageComponent? component = null) { if (!Resolve(target, ref component, false)) return false; return component.FreeLearnedSkills.Contains(skill); } /// /// Checks if the player can learn the specified skill. /// public bool CanLearnSkill(EntityUid target, ProtoId skill, CP14SkillStorageComponent? component = null) { if (!_proto.TryIndex(skill, out var indexedSkill)) return false; return CanLearnSkill(target, indexedSkill, component); } /// /// Checks if the player can learn the specified skill. /// public bool CanLearnSkill(EntityUid target, CP14SkillPrototype skill, CP14SkillStorageComponent? component = null) { if (!Resolve(target, ref component, false)) return false; if (!AllowedToLearn(target, skill, component)) return false; return true; } /// /// Is it allowed to learn this skill? The player may not have enough points to learn it, but has already met all the requirements to learn it. /// public bool AllowedToLearn(EntityUid target, CP14SkillPrototype skill, CP14SkillStorageComponent? component = null) { if (!Resolve(target, ref component, false)) return false; //Already learned if (HaveSkill(target, skill, component)) return false; //Check max cap if (component.SkillsSumExperience + skill.LearnCost > component.ExperienceMaxCap) return false; //Restrictions check foreach (var req in skill.Restrictions) { if (!req.Check(EntityManager, target, skill)) return false; } return true; } /// /// Tries to learn the specified skill for the player. /// public bool TryLearnSkill(EntityUid target, ProtoId skill, CP14SkillStorageComponent? component = null) { if (!Resolve(target, ref component, false)) return false; if (!CanLearnSkill(target, skill, component)) return false; if (!TryAddSkill(target, skill, component)) return false; return false; } /// /// Helper function to get the skill name for a given skill prototype. /// public string GetSkillName(ProtoId skill) { if (!_proto.TryIndex(skill, out var indexedSkill)) return string.Empty; if (indexedSkill.Name is not null) return Loc.GetString(indexedSkill.Name); if (indexedSkill.Effects.Count > 0) return indexedSkill.Effects.First().GetName(EntityManager, _proto) ?? string.Empty; return string.Empty; } /// /// Helper function to get the skill description for a given skill prototype. /// public string GetSkillDescription(ProtoId skill) { if (!_proto.TryIndex(skill, out var indexedSkill)) return string.Empty; if (indexedSkill.Desc is not null) return Loc.GetString(indexedSkill.Desc); var sb = new StringBuilder(); foreach (var effect in indexedSkill.Effects) { sb.Append(effect.GetDescription(EntityManager, _proto, skill) + "\n"); } return sb.ToString(); } /// /// Helper function to reset skills to only learned skills /// public bool TryResetSkills(EntityUid target, CP14SkillStorageComponent? component = null) { if (!Resolve(target, ref component, false)) { return false; } for(var i = component.LearnedSkills.Count - 1; i >= 0; i--) { if(HaveFreeSkill(target, component.LearnedSkills[i], component)) { continue; } TryRemoveSkill(target, component.LearnedSkills[i], component); } return true; } } [ByRefEvent] public record struct CP14SkillLearnedEvent(ProtoId Skill, EntityUid User);