Skill requirements (#1085)
* prerequites refactor * tiefling only spells * metamagic update * sort trying * goblin speed port
This commit is contained in:
@@ -138,11 +138,43 @@ public abstract partial class CP14SharedSkillSystem : EntitySystem
|
||||
public bool CanLearnSkill(EntityUid target,
|
||||
ProtoId<CP14SkillPrototype> skill,
|
||||
CP14SkillStorageComponent? component = null)
|
||||
{
|
||||
if (!_proto.TryIndex(skill, out var indexedSkill))
|
||||
return false;
|
||||
|
||||
return CanLearnSkill(target, indexedSkill, component);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the player can learn the specified skill.
|
||||
/// </summary>
|
||||
public bool CanLearnSkill(EntityUid target,
|
||||
CP14SkillPrototype skill,
|
||||
CP14SkillStorageComponent? component = null)
|
||||
{
|
||||
if (!Resolve(target, ref component, false))
|
||||
return false;
|
||||
|
||||
if (!_proto.TryIndex(skill, out var indexedSkill))
|
||||
if (!AllowedToLearn(target, skill, component))
|
||||
return false;
|
||||
|
||||
//Experience check
|
||||
if (!component.Progress.TryGetValue(skill.Tree, out var currentExp))
|
||||
return false;
|
||||
if (currentExp < skill.LearnCost)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 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.
|
||||
/// </summary>
|
||||
public bool AllowedToLearn(EntityUid target,
|
||||
CP14SkillPrototype skill,
|
||||
CP14SkillStorageComponent? component = null)
|
||||
{
|
||||
if (!Resolve(target, ref component, false))
|
||||
return false;
|
||||
|
||||
//Already learned
|
||||
@@ -150,22 +182,16 @@ public abstract partial class CP14SharedSkillSystem : EntitySystem
|
||||
return false;
|
||||
|
||||
//Check max cap
|
||||
if (component.SkillsSumExperience + indexedSkill.LearnCost >= component.ExperienceMaxCap)
|
||||
if (component.SkillsSumExperience + skill.LearnCost >= component.ExperienceMaxCap)
|
||||
return false;
|
||||
|
||||
//Prerequisite check
|
||||
foreach (var prerequisite in indexedSkill.Prerequisites)
|
||||
//Restrictions check
|
||||
foreach (var req in skill.Restrictions)
|
||||
{
|
||||
if (!HaveSkill(target, prerequisite, component))
|
||||
if (!req.Check(EntityManager, target))
|
||||
return false;
|
||||
}
|
||||
|
||||
//Experience check
|
||||
if (!component.Progress.TryGetValue(indexedSkill.Tree, out var currentExp))
|
||||
return false;
|
||||
if (currentExp < indexedSkill.LearnCost)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System.Linq;
|
||||
using Content.Shared._CP14.Skill.Components;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared.Administration;
|
||||
@@ -11,21 +12,43 @@ public abstract partial class CP14SharedSkillSystem
|
||||
{
|
||||
[Dependency] private readonly ISharedAdminManager _admin = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
private IEnumerable<CP14SkillPrototype>? _allSkills;
|
||||
private void InitializeAdmin()
|
||||
{
|
||||
SubscribeLocalEvent<CP14SkillStorageComponent, GetVerbsEvent<Verb>>(OnGetAdminVerbs);
|
||||
|
||||
SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnPrototypeReloaded);
|
||||
|
||||
UpdateCachedSkill();
|
||||
}
|
||||
|
||||
private void OnPrototypeReloaded(PrototypesReloadedEventArgs ev)
|
||||
{
|
||||
if (!ev.WasModified<CP14SkillPrototype>())
|
||||
return;
|
||||
|
||||
UpdateCachedSkill();
|
||||
}
|
||||
|
||||
private void UpdateCachedSkill()
|
||||
{
|
||||
_allSkills = _proto.EnumeratePrototypes<CP14SkillPrototype>().ToList().OrderBy(skill => skill.Tree.Id).ThenBy(skill => skill.Name);
|
||||
}
|
||||
|
||||
|
||||
private void OnGetAdminVerbs(Entity<CP14SkillStorageComponent> ent, ref GetVerbsEvent<Verb> args)
|
||||
{
|
||||
if (!_admin.HasAdminFlag(args.User, AdminFlags.Admin))
|
||||
return;
|
||||
|
||||
if (_allSkills is null)
|
||||
return;
|
||||
|
||||
var target = args.Target;
|
||||
|
||||
//Add Skill
|
||||
foreach (var skill in _proto.EnumeratePrototypes<CP14SkillPrototype>())
|
||||
foreach (var skill in _allSkills)
|
||||
{
|
||||
if (ent.Comp.LearnedSkills.Contains(skill))
|
||||
continue;
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
using Content.Shared.Actions;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Specials;
|
||||
namespace Content.Shared._CP14.Skill.Effects;
|
||||
|
||||
public sealed partial class AddAction : CP14SkillEffect
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public EntProtoId Action;
|
||||
|
||||
public override void AddSkill(EntityManager entManager, EntityUid target)
|
||||
public override void AddSkill(IEntityManager entManager, EntityUid target)
|
||||
{
|
||||
var actionsSystem = entManager.System<SharedActionsSystem>();
|
||||
|
||||
actionsSystem.AddAction(target, Action);
|
||||
}
|
||||
|
||||
public override void RemoveSkill(EntityManager entManager, EntityUid target)
|
||||
public override void RemoveSkill(IEntityManager entManager, EntityUid target)
|
||||
{
|
||||
var actionsSystem = entManager.System<SharedActionsSystem>();
|
||||
|
||||
@@ -34,19 +34,13 @@ public sealed partial class AddAction : CP14SkillEffect
|
||||
}
|
||||
}
|
||||
|
||||
public override string? GetName(EntityManager entMagager, IPrototypeManager protoManager)
|
||||
public override string? GetName(IEntityManager entMagager, IPrototypeManager protoManager)
|
||||
{
|
||||
if (!protoManager.TryIndex(Action, out var indexedAction))
|
||||
return String.Empty;
|
||||
|
||||
return indexedAction.Name;
|
||||
return !protoManager.TryIndex(Action, out var indexedAction) ? string.Empty : indexedAction.Name;
|
||||
}
|
||||
|
||||
public override string? GetDescription(EntityManager entMagager, IPrototypeManager protoManager)
|
||||
public override string? GetDescription(IEntityManager entMagager, IPrototypeManager protoManager)
|
||||
{
|
||||
if (!protoManager.TryIndex(Action, out var indexedAction))
|
||||
return String.Empty;
|
||||
|
||||
return indexedAction.Description;
|
||||
return !protoManager.TryIndex(Action, out var indexedAction) ? string.Empty : indexedAction.Description;
|
||||
}
|
||||
}
|
||||
17
Content.Shared/_CP14/Skill/Effects/CP14SkillEffect.cs
Normal file
17
Content.Shared/_CP14/Skill/Effects/CP14SkillEffect.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Effects;
|
||||
|
||||
[ImplicitDataDefinitionForInheritors]
|
||||
[MeansImplicitUse]
|
||||
public abstract partial class CP14SkillEffect
|
||||
{
|
||||
public abstract void AddSkill(IEntityManager entManager, EntityUid target);
|
||||
|
||||
public abstract void RemoveSkill(IEntityManager entManager, EntityUid target);
|
||||
|
||||
public abstract string? GetName(IEntityManager entMagager, IPrototypeManager protoManager);
|
||||
|
||||
public abstract string? GetDescription(IEntityManager entMagager, IPrototypeManager protoManager);
|
||||
}
|
||||
69
Content.Shared/_CP14/Skill/Effects/ReplaceAction.cs
Normal file
69
Content.Shared/_CP14/Skill/Effects/ReplaceAction.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using Content.Shared.Actions;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Effects;
|
||||
|
||||
public sealed partial class ReplaceAction : CP14SkillEffect
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public EntProtoId OldAction;
|
||||
|
||||
[DataField(required: true)]
|
||||
public EntProtoId NewAction;
|
||||
|
||||
public override void AddSkill(IEntityManager entManager, EntityUid target)
|
||||
{
|
||||
var actionsSystem = entManager.System<SharedActionsSystem>();
|
||||
|
||||
//Remove old action
|
||||
foreach (var (uid, _) in actionsSystem.GetActions(target))
|
||||
{
|
||||
if (!entManager.TryGetComponent<MetaDataComponent>(uid, out var metaData))
|
||||
continue;
|
||||
|
||||
if (metaData.EntityPrototype == null)
|
||||
continue;
|
||||
|
||||
if (metaData.EntityPrototype != OldAction)
|
||||
continue;
|
||||
|
||||
actionsSystem.RemoveAction(target, uid);
|
||||
}
|
||||
|
||||
//Add new one
|
||||
actionsSystem.AddAction(target, NewAction);
|
||||
}
|
||||
|
||||
public override void RemoveSkill(IEntityManager entManager, EntityUid target)
|
||||
{
|
||||
var actionsSystem = entManager.System<SharedActionsSystem>();
|
||||
|
||||
//Remove old action
|
||||
foreach (var (uid, _) in actionsSystem.GetActions(target))
|
||||
{
|
||||
if (!entManager.TryGetComponent<MetaDataComponent>(uid, out var metaData))
|
||||
continue;
|
||||
|
||||
if (metaData.EntityPrototype == null)
|
||||
continue;
|
||||
|
||||
if (metaData.EntityPrototype != NewAction)
|
||||
continue;
|
||||
|
||||
actionsSystem.RemoveAction(target, uid);
|
||||
}
|
||||
|
||||
//Add new one
|
||||
actionsSystem.AddAction(target, OldAction);
|
||||
}
|
||||
|
||||
public override string? GetName(IEntityManager entMagager, IPrototypeManager protoManager)
|
||||
{
|
||||
return !protoManager.TryIndex(NewAction, out var indexedAction) ? string.Empty : indexedAction.Name;
|
||||
}
|
||||
|
||||
public override string? GetDescription(IEntityManager entMagager, IPrototypeManager protoManager)
|
||||
{
|
||||
return !protoManager.TryIndex(NewAction, out var indexedAction) ? string.Empty : indexedAction.Description;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Numerics;
|
||||
using Content.Shared._CP14.Skill.Specials;
|
||||
using Content.Shared._CP14.Skill.Effects;
|
||||
using Content.Shared._CP14.Skill.Restrictions;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -37,12 +38,6 @@ public sealed partial class CP14SkillPrototype : IPrototype
|
||||
[DataField]
|
||||
public float LearnCost = 1f;
|
||||
|
||||
/// <summary>
|
||||
/// Prerequisites for this skill. This is used to determine if the player can learn the skill. If the player does not have all the prerequisites, they cannot learn the skill.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public HashSet<ProtoId<CP14SkillPrototype>> Prerequisites = new();
|
||||
|
||||
/// <summary>
|
||||
/// Skill UI position. This is used to determine where the skill will be displayed in the skill tree UI.
|
||||
/// </summary>
|
||||
@@ -61,4 +56,10 @@ public sealed partial class CP14SkillPrototype : IPrototype
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public CP14SkillEffect? Effect;
|
||||
|
||||
/// <summary>
|
||||
/// Skill restriction. Limiters on learning. Any reason why a player cannot learn this skill.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<CP14SkillRestriction> Restrictions = new();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Restrictions;
|
||||
|
||||
[ImplicitDataDefinitionForInheritors]
|
||||
[MeansImplicitUse]
|
||||
public abstract partial class CP14SkillRestriction
|
||||
{
|
||||
public abstract bool Check(IEntityManager entManager, EntityUid target);
|
||||
|
||||
public abstract string GetDescription(IEntityManager entManager, IPrototypeManager protoManager);
|
||||
}
|
||||
27
Content.Shared/_CP14/Skill/Restrictions/NeedPrerequisite.cs
Normal file
27
Content.Shared/_CP14/Skill/Restrictions/NeedPrerequisite.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using Content.Shared._CP14.Skill.Components;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Restrictions;
|
||||
|
||||
public sealed partial class NeedPrerequisite : CP14SkillRestriction
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public ProtoId<CP14SkillPrototype> Prerequisite = new();
|
||||
|
||||
public override bool Check(IEntityManager entManager, EntityUid target)
|
||||
{
|
||||
if (!entManager.TryGetComponent<CP14SkillStorageComponent>(target, out var skillStorage))
|
||||
return false;
|
||||
|
||||
var learned = skillStorage.LearnedSkills;
|
||||
return learned.Contains(Prerequisite);
|
||||
}
|
||||
|
||||
public override string GetDescription(IEntityManager entManager, IPrototypeManager protoManager)
|
||||
{
|
||||
var skillSystem = entManager.System<CP14SharedSkillSystem>();
|
||||
|
||||
return Loc.GetString("cp14-skill-req-prerequisite", ("name", skillSystem.GetSkillName(Prerequisite)));
|
||||
}
|
||||
}
|
||||
26
Content.Shared/_CP14/Skill/Restrictions/SpeciesWhitelist.cs
Normal file
26
Content.Shared/_CP14/Skill/Restrictions/SpeciesWhitelist.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Restrictions;
|
||||
|
||||
public sealed partial class SpeciesWhitelist : CP14SkillRestriction
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public ProtoId<SpeciesPrototype> Species = new();
|
||||
|
||||
public override bool Check(IEntityManager entManager, EntityUid target)
|
||||
{
|
||||
if (!entManager.TryGetComponent<HumanoidAppearanceComponent>(target, out var appearance))
|
||||
return false;
|
||||
|
||||
return appearance.Species == Species;
|
||||
}
|
||||
|
||||
public override string GetDescription(IEntityManager entManager, IPrototypeManager protoManager)
|
||||
{
|
||||
var species = protoManager.Index(Species);
|
||||
|
||||
return Loc.GetString("cp14-skill-req-species", ("name", Loc.GetString(species.Name)));
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Specials;
|
||||
|
||||
[ImplicitDataDefinitionForInheritors]
|
||||
[MeansImplicitUse]
|
||||
public abstract partial class CP14SkillEffect
|
||||
{
|
||||
public abstract void AddSkill(EntityManager entManager, EntityUid target);
|
||||
|
||||
public abstract void RemoveSkill(EntityManager entManager, EntityUid target);
|
||||
|
||||
public abstract string? GetName(EntityManager entMagager, IPrototypeManager protoManager);
|
||||
|
||||
public abstract string? GetDescription(EntityManager entMagager, IPrototypeManager protoManager);
|
||||
}
|
||||
Reference in New Issue
Block a user