Skill progression system [Draft] (#1056)
* fuck all * clean up * remove knowledge books * Update base.yml * cl * fix #991 * fix * Update subgamemodes.yml * manual migration + recipes fix * Update comoss.yml * setup data * setup skills systems * more blacksmithing skills * Update base.yml * Create CP14SkillEffectAction.cs * skill button returns * base graph UI window * skill tree drawing * UI improve * pyro setup * skill trees selection, dragging control * refactor skill system: rename Skills to LearnedSkills, add experience tracking and learning logic * Create available.png * skill description generation setup * auto parsing skill names and descriptions * Hydrosophistry * water light fire and metamagic ported to skill tre * ice dagger spell returns * Update ice_dagger.yml * delete old files * Update modular_garde.yml * ice arrow spell * link graph with parallax * show experience counter * polish * puf * p * pipap * finally ready to merg? * fix * fix 2
This commit is contained in:
230
Content.Shared/_CP14/Skill/CP14SharedSkillSystem.cs
Normal file
230
Content.Shared/_CP14/Skill/CP14SharedSkillSystem.cs
Normal file
@@ -0,0 +1,230 @@
|
||||
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
|
||||
{
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
InitializeAdmin();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Directly adds the skill to the player, bypassing any checks.
|
||||
/// </summary>
|
||||
public bool TryAddSkill(EntityUid target,
|
||||
ProtoId<CP14SkillPrototype> skill,
|
||||
CP14SkillStorageComponent? component = null)
|
||||
{
|
||||
if (!Resolve(target, ref component, false))
|
||||
return false;
|
||||
|
||||
if (component.LearnedSkills.Contains(skill))
|
||||
return false;
|
||||
|
||||
if (!_proto.TryIndex(skill, out var indexedSkill))
|
||||
return false;
|
||||
|
||||
if (indexedSkill.Effect is not null)
|
||||
{
|
||||
indexedSkill.Effect.AddSkill(EntityManager, target);
|
||||
}
|
||||
|
||||
component.SkillsSumExperience += indexedSkill.LearnCost;
|
||||
|
||||
component.LearnedSkills.Add(skill);
|
||||
Dirty(target, component);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the skill from the player, bypassing any checks.
|
||||
/// </summary>
|
||||
public bool TryRemoveSkill(EntityUid target,
|
||||
ProtoId<CP14SkillPrototype> 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;
|
||||
|
||||
if (indexedSkill.Effect is not null)
|
||||
{
|
||||
indexedSkill.Effect.RemoveSkill(EntityManager, target);
|
||||
}
|
||||
|
||||
component.SkillsSumExperience -= indexedSkill.LearnCost;
|
||||
|
||||
Dirty(target, component);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the player has the skill.
|
||||
/// </summary>
|
||||
public bool HaveSkill(EntityUid target,
|
||||
ProtoId<CP14SkillPrototype> skill,
|
||||
CP14SkillStorageComponent? component = null)
|
||||
{
|
||||
if (!Resolve(target, ref component, false))
|
||||
return false;
|
||||
|
||||
return component.LearnedSkills.Contains(skill);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds experience to the specified skill tree for the player.
|
||||
/// </summary>
|
||||
public bool TryAddExperience(EntityUid target,
|
||||
ProtoId<CP14SkillTreePrototype> tree,
|
||||
FixedPoint2 exp,
|
||||
CP14SkillStorageComponent? component = null)
|
||||
{
|
||||
if (!Resolve(target, ref component, false))
|
||||
return false;
|
||||
|
||||
if (component.Progress.TryGetValue(tree, out var currentExp))
|
||||
{
|
||||
// If the tree already exists, add experience to it
|
||||
component.Progress[tree] = currentExp + exp;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If the tree doesn't exist, initialize it with the experience
|
||||
component.Progress[tree] = exp;
|
||||
}
|
||||
|
||||
Dirty(target, component);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes experience from the specified skill tree for the player.
|
||||
/// </summary>
|
||||
public bool TryRemoveExperience(EntityUid target,
|
||||
ProtoId<CP14SkillTreePrototype> tree,
|
||||
FixedPoint2 exp,
|
||||
CP14SkillStorageComponent? component = null)
|
||||
{
|
||||
if (!Resolve(target, ref component, false))
|
||||
return false;
|
||||
|
||||
if (!component.Progress.TryGetValue(tree, out var currentExp))
|
||||
return false;
|
||||
|
||||
if (currentExp < exp)
|
||||
return false;
|
||||
|
||||
component.Progress[tree] = FixedPoint2.Max(0, component.Progress[tree] - exp);
|
||||
|
||||
Dirty(target, component);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the player can learn the specified skill.
|
||||
/// </summary>
|
||||
public bool CanLearnSkill(EntityUid target,
|
||||
ProtoId<CP14SkillPrototype> skill,
|
||||
CP14SkillStorageComponent? component = null)
|
||||
{
|
||||
if (!Resolve(target, ref component, false))
|
||||
return false;
|
||||
|
||||
if (!_proto.TryIndex(skill, out var indexedSkill))
|
||||
return false;
|
||||
|
||||
//Already learned
|
||||
if (HaveSkill(target, skill, component))
|
||||
return false;
|
||||
|
||||
//Check max cap
|
||||
if (component.SkillsSumExperience + indexedSkill.LearnCost >= component.ExperienceMaxCap)
|
||||
return false;
|
||||
|
||||
//Prerequisite check
|
||||
foreach (var prerequisite in indexedSkill.Prerequisites)
|
||||
{
|
||||
if (!HaveSkill(target, prerequisite, component))
|
||||
return false;
|
||||
}
|
||||
|
||||
//Experience check
|
||||
if (!component.Progress.TryGetValue(indexedSkill.Tree, out var currentExp))
|
||||
return false;
|
||||
if (currentExp < indexedSkill.LearnCost)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to learn the specified skill for the player.
|
||||
/// </summary>
|
||||
public bool TryLearnSkill(EntityUid target,
|
||||
ProtoId<CP14SkillPrototype> skill,
|
||||
CP14SkillStorageComponent? component = null)
|
||||
{
|
||||
if (!Resolve(target, ref component, false))
|
||||
return false;
|
||||
|
||||
if (!_proto.TryIndex(skill, out var indexedSkill))
|
||||
return false;
|
||||
|
||||
if (!CanLearnSkill(target, skill, component))
|
||||
return false;
|
||||
|
||||
if (!TryRemoveExperience(target, indexedSkill.Tree, indexedSkill.LearnCost, component))
|
||||
return false;
|
||||
|
||||
if (!TryAddSkill(target, skill, component))
|
||||
return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function to get the skill name for a given skill prototype.
|
||||
/// </summary>
|
||||
public string GetSkillName(ProtoId<CP14SkillPrototype> skill)
|
||||
{
|
||||
if (!_proto.TryIndex(skill, out var indexedSkill))
|
||||
return string.Empty;
|
||||
|
||||
if (indexedSkill.Name != null)
|
||||
return Loc.GetString(indexedSkill.Name);
|
||||
|
||||
if (indexedSkill.Effect != null)
|
||||
return indexedSkill.Effect.GetName(EntityManager, _proto) ?? string.Empty;
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Helper function to get the skill description for a given skill prototype.
|
||||
/// </summary>
|
||||
public string GetSkillDescription(ProtoId<CP14SkillPrototype> skill)
|
||||
{
|
||||
if (!_proto.TryIndex(skill, out var indexedSkill))
|
||||
return string.Empty;
|
||||
|
||||
if (indexedSkill.Desc != null)
|
||||
return Loc.GetString(indexedSkill.Desc);
|
||||
|
||||
if (indexedSkill.Effect != null)
|
||||
return indexedSkill.Effect.GetDescription(EntityManager, _proto) ?? string.Empty;
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
67
Content.Shared/_CP14/Skill/CP14SkillSystem.Admin.cs
Normal file
67
Content.Shared/_CP14/Skill/CP14SkillSystem.Admin.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using Content.Shared._CP14.Skill.Components;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Administration.Managers;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill;
|
||||
|
||||
public abstract partial class CP14SharedSkillSystem
|
||||
{
|
||||
[Dependency] private readonly ISharedAdminManager _admin = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
private void InitializeAdmin()
|
||||
{
|
||||
SubscribeLocalEvent<CP14SkillStorageComponent, GetVerbsEvent<Verb>>(OnGetAdminVerbs);
|
||||
}
|
||||
|
||||
private void OnGetAdminVerbs(Entity<CP14SkillStorageComponent> ent, ref GetVerbsEvent<Verb> args)
|
||||
{
|
||||
if (!_admin.HasAdminFlag(args.User, AdminFlags.Admin))
|
||||
return;
|
||||
|
||||
|
||||
var target = args.Target;
|
||||
|
||||
//Add Skill
|
||||
foreach (var skill in _proto.EnumeratePrototypes<CP14SkillPrototype>())
|
||||
{
|
||||
if (ent.Comp.LearnedSkills.Contains(skill))
|
||||
continue;
|
||||
|
||||
var name = Loc.GetString(GetSkillName(skill));
|
||||
args.Verbs.Add(new Verb
|
||||
{
|
||||
Text = name,
|
||||
Message = name + ": " + Loc.GetString(GetSkillDescription(skill)),
|
||||
Category = VerbCategory.CP14AdminSkillAdd,
|
||||
Icon = skill.Icon,
|
||||
Act = () =>
|
||||
{
|
||||
TryAddSkill(target, skill);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
//Remove Skill
|
||||
foreach (var skill in ent.Comp.LearnedSkills)
|
||||
{
|
||||
if (!_proto.TryIndex(skill, out var indexedSkill))
|
||||
continue;
|
||||
|
||||
var name = Loc.GetString(GetSkillName(skill));
|
||||
args.Verbs.Add(new Verb
|
||||
{
|
||||
Text = name,
|
||||
Message = name + ": " + Loc.GetString(GetSkillDescription(skill)),
|
||||
Category = VerbCategory.CP14AdminSkillRemove,
|
||||
Icon = indexedSkill.Icon,
|
||||
Act = () =>
|
||||
{
|
||||
TryRemoveSkill(target, skill);
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Content.Shared/_CP14/Skill/CP14SkillSystem.Learning.cs
Normal file
48
Content.Shared/_CP14/Skill/CP14SkillSystem.Learning.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using Content.Shared._CP14.Skill.Components;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared.Bed.Sleep;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill;
|
||||
|
||||
public abstract partial class CP14SharedSkillSystem
|
||||
{
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly ExamineSystemShared _examine = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
|
||||
public void GiveExperienceInRadius(EntityCoordinates position, ProtoId<CP14SkillTreePrototype> tree, FixedPoint2 points, float radius = 5)
|
||||
{
|
||||
var entities = _lookup.GetEntitiesInRange<CP14SkillStorageComponent>(position, radius, LookupFlags.Uncontained);
|
||||
|
||||
foreach (var ent in entities)
|
||||
{
|
||||
//Cant learn if the position is not in range or obstructed
|
||||
if (!_examine.InRangeUnOccluded(ent, position, radius))
|
||||
continue;
|
||||
|
||||
//Cant learn when dead
|
||||
if (TryComp<MobStateComponent>(ent, out var mobState) && !_mobState.IsAlive(ent, mobState))
|
||||
continue;
|
||||
|
||||
//Cant learn if the entity is sleeping
|
||||
if (HasComp<SleepingComponent>(ent))
|
||||
continue;
|
||||
|
||||
TryAddExperience(ent, tree, points);
|
||||
}
|
||||
}
|
||||
|
||||
public void GiveExperienceInRadius(EntityUid uid,
|
||||
ProtoId<CP14SkillTreePrototype> tree,
|
||||
FixedPoint2 points,
|
||||
float radius = 5)
|
||||
{
|
||||
GiveExperienceInRadius(Transform(uid).Coordinates, tree, points, radius);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Component that stores the skills learned by a player and their progress in the skill trees.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
|
||||
[Access(typeof(CP14SharedSkillSystem))]
|
||||
public sealed partial class CP14SkillStorageComponent : Component
|
||||
{
|
||||
[DataField, AutoNetworkedField]
|
||||
public List<ProtoId<CP14SkillPrototype>> LearnedSkills = new();
|
||||
|
||||
/// <summary>
|
||||
/// The number of experience points spent on skills. Technically this could be calculated via LearnedSkills, but this is a cached value for optimization.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public FixedPoint2 SkillsSumExperience = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Keeps track of progress points in the knowledge areas available to the player. Important: The absence of a specific area means that the player CANNOT progress in that area.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public Dictionary<ProtoId<CP14SkillTreePrototype>, FixedPoint2> Progress = new();
|
||||
|
||||
/// <summary>
|
||||
/// The maximum ceiling of experience points that can be spent on learning skills. Not tied to a category.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public FixedPoint2 ExperienceMaxCap = 10;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raised when a player attempts to learn a skill. This is sent from the client to the server.
|
||||
/// </summary>
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class CP14TryLearnSkillMessage(NetEntity entity, ProtoId<CP14SkillPrototype> skill) : EntityEventArgs
|
||||
{
|
||||
public readonly NetEntity Entity = entity;
|
||||
public readonly ProtoId<CP14SkillPrototype> Skill = skill;
|
||||
}
|
||||
64
Content.Shared/_CP14/Skill/Prototypes/CP14SkillPrototype.cs
Normal file
64
Content.Shared/_CP14/Skill/Prototypes/CP14SkillPrototype.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System.Numerics;
|
||||
using Content.Shared._CP14.Skill.Specials;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Prototypes;
|
||||
|
||||
/// <summary>
|
||||
/// A skill that can be learned by the player. Skills are grouped into trees, and each skill has a cost to learn, prerequisites, and an effect.
|
||||
/// </summary>
|
||||
[Prototype("cp14Skill")]
|
||||
public sealed partial class CP14SkillPrototype : IPrototype
|
||||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Skill Title. If you leave null, the name will try to generate from Effect.GetName()
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public LocId? Name;
|
||||
|
||||
/// <summary>
|
||||
/// Skill Description. If you leave null, the description will try to generate from Effect.GetDescription()
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public LocId? Desc;
|
||||
|
||||
/// <summary>
|
||||
/// The tree this skill belongs to. This is used to group skills together in the UI.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public ProtoId<CP14SkillTreePrototype> Tree = default!;
|
||||
|
||||
/// <summary>
|
||||
/// The cost to learn this skill. This is used to determine how many progress points are needed to learn the skill.
|
||||
/// </summary>
|
||||
[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>
|
||||
[DataField(required: true)]
|
||||
public Vector2 SkillUiPosition = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Icon for the skill. This is used to display the skill in the skill tree UI.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public SpriteSpecifier Icon = default!;
|
||||
|
||||
/// <summary>
|
||||
/// Skill effect. This is used to determine what happens when the player learns the skill. If you leave null, the skill will not have any effect.
|
||||
/// But the presence of the skill itself can affect some systems that check for the presence of certain skills.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public CP14SkillEffect? Effect;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Prototypes;
|
||||
|
||||
/// <summary>
|
||||
/// A group of skills combined into one “branch”
|
||||
/// </summary>
|
||||
[Prototype("cp14SkillTree")]
|
||||
public sealed partial class CP14SkillTreePrototype : IPrototype
|
||||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
[DataField(required: true)]
|
||||
public LocId Name;
|
||||
|
||||
[DataField]
|
||||
public SpriteSpecifier FrameIcon = new SpriteSpecifier.Rsi(new ResPath("/Textures/_CP14/Interface/Skills/default.rsi"), "frame");
|
||||
|
||||
[DataField]
|
||||
public SpriteSpecifier HoveredIcon = new SpriteSpecifier.Rsi(new ResPath("/Textures/_CP14/Interface/Skills/default.rsi"), "hovered");
|
||||
|
||||
[DataField]
|
||||
public SpriteSpecifier SelectedIcon = new SpriteSpecifier.Rsi(new ResPath("/Textures/_CP14/Interface/Skills/default.rsi"), "selected");
|
||||
|
||||
[DataField]
|
||||
public SpriteSpecifier LearnedIcon = new SpriteSpecifier.Rsi(new ResPath("/Textures/_CP14/Interface/Skills/default.rsi"), "learned");
|
||||
|
||||
[DataField]
|
||||
public SpriteSpecifier AvailableIcon = new SpriteSpecifier.Rsi(new ResPath("/Textures/_CP14/Interface/Skills/default.rsi"), "available");
|
||||
|
||||
[DataField]
|
||||
public string Parallax = "AspidParallax";
|
||||
|
||||
[DataField]
|
||||
public LocId? Desc;
|
||||
|
||||
[DataField]
|
||||
public Color Color;
|
||||
|
||||
[DataField]
|
||||
public SoundSpecifier LearnSound = new SoundCollectionSpecifier("CP14LearnSkill");
|
||||
}
|
||||
52
Content.Shared/_CP14/Skill/Specials/AddAction.cs
Normal file
52
Content.Shared/_CP14/Skill/Specials/AddAction.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using Content.Shared.Actions;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Specials;
|
||||
|
||||
public sealed partial class AddAction : CP14SkillEffect
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public EntProtoId Action;
|
||||
|
||||
public override void AddSkill(EntityManager entManager, EntityUid target)
|
||||
{
|
||||
var actionsSystem = entManager.System<SharedActionsSystem>();
|
||||
|
||||
actionsSystem.AddAction(target, Action);
|
||||
}
|
||||
|
||||
public override void RemoveSkill(EntityManager entManager, EntityUid target)
|
||||
{
|
||||
var actionsSystem = entManager.System<SharedActionsSystem>();
|
||||
|
||||
foreach (var (uid, _) in actionsSystem.GetActions(target))
|
||||
{
|
||||
if (!entManager.TryGetComponent<MetaDataComponent>(uid, out var metaData))
|
||||
continue;
|
||||
|
||||
if (metaData.EntityPrototype == null)
|
||||
continue;
|
||||
|
||||
if (metaData.EntityPrototype != Action)
|
||||
continue;
|
||||
|
||||
actionsSystem.RemoveAction(target, uid);
|
||||
}
|
||||
}
|
||||
|
||||
public override string? GetName(EntityManager entMagager, IPrototypeManager protoManager)
|
||||
{
|
||||
if (!protoManager.TryIndex(Action, out var indexedAction))
|
||||
return String.Empty;
|
||||
|
||||
return indexedAction.Name;
|
||||
}
|
||||
|
||||
public override string? GetDescription(EntityManager entMagager, IPrototypeManager protoManager)
|
||||
{
|
||||
if (!protoManager.TryIndex(Action, out var indexedAction))
|
||||
return String.Empty;
|
||||
|
||||
return indexedAction.Description;
|
||||
}
|
||||
}
|
||||
17
Content.Shared/_CP14/Skill/Specials/CP14SkillEffect.cs
Normal file
17
Content.Shared/_CP14/Skill/Specials/CP14SkillEffect.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
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