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:
@@ -84,6 +84,9 @@ namespace Content.Client.Input
|
||||
human.AddFunction(ContentKeyFunctions.Arcade1);
|
||||
human.AddFunction(ContentKeyFunctions.Arcade2);
|
||||
human.AddFunction(ContentKeyFunctions.Arcade3);
|
||||
//CP14 Keys
|
||||
human.AddFunction(ContentKeyFunctions.CP14OpenSkillMenu);
|
||||
//CP14 Keys end
|
||||
|
||||
// actions should be common (for ghosts, mobs, etc)
|
||||
common.AddFunction(ContentKeyFunctions.OpenActionsMenu);
|
||||
@@ -123,10 +126,6 @@ namespace Content.Client.Input
|
||||
common.AddFunction(ContentKeyFunctions.OpenDecalSpawnWindow);
|
||||
common.AddFunction(ContentKeyFunctions.OpenAdminMenu);
|
||||
common.AddFunction(ContentKeyFunctions.OpenGuidebook);
|
||||
|
||||
//CP14 Keys
|
||||
human.AddFunction(ContentKeyFunctions.CP14OpenKnowledgeMenu);
|
||||
//CP14 Keys end
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -312,9 +312,8 @@ namespace Content.Client.Options.UI.Tabs
|
||||
|
||||
//CP14
|
||||
AddHeader("ui-options-header-cp14");
|
||||
AddButton(ContentKeyFunctions.CP14OpenKnowledgeMenu);
|
||||
AddButton(ContentKeyFunctions.CP14OpenSkillMenu);
|
||||
//CP14 end
|
||||
|
||||
foreach (var control in _keyControls.Values)
|
||||
{
|
||||
UpdateKeyControl(control);
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System.Numerics;
|
||||
using System.Numerics;
|
||||
using Content.Client.Parallax.Data;
|
||||
using Content.Client.Parallax.Managers;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.ViewVariables;
|
||||
@@ -17,27 +19,50 @@ public sealed class ParallaxControl : Control
|
||||
[Dependency] private readonly IParallaxManager _parallaxManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
private string _parallaxPrototype = "FastSpace";
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)] public Vector2 Offset { get; set; }
|
||||
[ViewVariables(VVAccess.ReadWrite)] public float SpeedX { get; set; } = 0.0f;
|
||||
[ViewVariables(VVAccess.ReadWrite)] public float SpeedY { get; set; } = 0.0f;
|
||||
[ViewVariables(VVAccess.ReadWrite)] public float ScaleX { get; set; } = 1.0f;
|
||||
[ViewVariables(VVAccess.ReadWrite)] public float ScaleY { get; set; } = 1.0f;
|
||||
[ViewVariables(VVAccess.ReadWrite)] public string ParallaxPrototype
|
||||
{
|
||||
get => _parallaxPrototype;
|
||||
set
|
||||
{
|
||||
_parallaxPrototype = value;
|
||||
_parallaxManager.LoadParallaxByName(value);
|
||||
}
|
||||
}
|
||||
|
||||
public ParallaxControl()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
Offset = new Vector2(_random.Next(0, 1000), _random.Next(0, 1000));
|
||||
|
||||
RectClipContent = true;
|
||||
_parallaxManager.LoadParallaxByName("FastSpace");
|
||||
_parallaxManager.LoadParallaxByName(_parallaxPrototype);
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
foreach (var layer in _parallaxManager.GetParallaxLayers("FastSpace"))
|
||||
var currentTime = (float) _timing.RealTime.TotalSeconds;
|
||||
var offset = Offset + new Vector2(currentTime * SpeedX, currentTime * SpeedY);
|
||||
|
||||
foreach (var layer in _parallaxManager.GetParallaxLayers(_parallaxPrototype))
|
||||
{
|
||||
var tex = layer.Texture;
|
||||
var texSize = (tex.Size.X * (int) Size.X, tex.Size.Y * (int) Size.X) * layer.Config.Scale.Floored() / 1920;
|
||||
var texSize = new Vector2i(
|
||||
(int)(tex.Size.X * Size.X * layer.Config.Scale.X / 1920 * ScaleX),
|
||||
(int)(tex.Size.Y * Size.X * layer.Config.Scale.Y / 1920 * ScaleY)
|
||||
);
|
||||
var ourSize = PixelSize;
|
||||
|
||||
var currentTime = (float) _timing.RealTime.TotalSeconds;
|
||||
var offset = Offset + new Vector2(currentTime * 100f, currentTime * 0f);
|
||||
//Protection from division by zero.
|
||||
texSize.X = Math.Max(texSize.X, 1);
|
||||
texSize.Y = Math.Max(texSize.Y, 1);
|
||||
|
||||
if (layer.Config.Tiled)
|
||||
{
|
||||
|
||||
@@ -24,7 +24,7 @@ public sealed class GameTopMenuBarUIController : UIController
|
||||
[Dependency] private readonly SandboxUIController _sandbox = default!;
|
||||
[Dependency] private readonly GuidebookUIController _guidebook = default!;
|
||||
[Dependency] private readonly EmotesUIController _emotes = default!;
|
||||
[Dependency] private readonly CP14KnowledgeUIController _knowledge = default!; //CP14
|
||||
[Dependency] private readonly CP14SkillUIController _skill = default!; //CP14
|
||||
|
||||
private GameTopMenuBar? GameTopMenuBar => UIManager.GetActiveUIWidgetOrNull<GameTopMenuBar>();
|
||||
|
||||
@@ -48,7 +48,7 @@ public sealed class GameTopMenuBarUIController : UIController
|
||||
_action.UnloadButton();
|
||||
_sandbox.UnloadButton();
|
||||
_emotes.UnloadButton();
|
||||
_knowledge.UnloadButton(); //CP14
|
||||
_skill.UnloadButton(); //CP14
|
||||
}
|
||||
|
||||
public void LoadButtons()
|
||||
@@ -62,6 +62,6 @@ public sealed class GameTopMenuBarUIController : UIController
|
||||
_action.LoadButton();
|
||||
_sandbox.LoadButton();
|
||||
_emotes.LoadButton();
|
||||
_knowledge.LoadButton(); //CP14
|
||||
_skill.LoadButton(); //CP14
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,11 +35,11 @@
|
||||
/>
|
||||
<!-- CP14 UI part -->
|
||||
<ui:MenuButton
|
||||
Name="CP14KnowledgeButton"
|
||||
Name="CP14SkillButton"
|
||||
Access="Internal"
|
||||
Icon="{xe:Tex '/Textures/Interface/students-cap.svg.192dpi.png'}"
|
||||
ToolTip="{Loc 'cp14-game-hud-open-knowledge-menu-button-tooltip'}"
|
||||
BoundKey = "{x:Static is:ContentKeyFunctions.CP14OpenKnowledgeMenu}"
|
||||
ToolTip="{Loc 'cp14-game-hud-open-skill-menu-button-tooltip'}"
|
||||
BoundKey = "{x:Static is:ContentKeyFunctions.CP14OpenSkillMenu}"
|
||||
MinSize="42 64"
|
||||
HorizontalExpand="True"
|
||||
AppendStyleClass="{x:Static style:StyleBase.ButtonSquare}"
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
using Content.Shared._CP14.Knowledge;
|
||||
using Content.Shared._CP14.Knowledge.Events;
|
||||
using Content.Shared._CP14.Knowledge.Prototypes;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._CP14.Knowledge;
|
||||
|
||||
public sealed class ClientCP14KnowledgeSystem : SharedCP14KnowledgeSystem
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _players = default!;
|
||||
|
||||
public event Action<KnowledgeData>? OnKnowledgeUpdate;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeNetworkEvent<CP14KnowledgeInfoEvent>(OnCharacterKnowledgeEvent);
|
||||
}
|
||||
|
||||
public void RequestKnowledgeInfo()
|
||||
{
|
||||
var entity = _players.LocalEntity;
|
||||
if (entity is null)
|
||||
return;
|
||||
|
||||
RaiseNetworkEvent(new CP14RequestKnowledgeInfoEvent(GetNetEntity(entity.Value)));
|
||||
}
|
||||
|
||||
private void OnCharacterKnowledgeEvent(CP14KnowledgeInfoEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
var entity = GetEntity(msg.NetEntity);
|
||||
var data = new KnowledgeData(entity, msg.AllKnowledge);
|
||||
|
||||
OnKnowledgeUpdate?.Invoke(data);
|
||||
}
|
||||
|
||||
public readonly record struct KnowledgeData(
|
||||
EntityUid Entity,
|
||||
HashSet<ProtoId<CP14KnowledgePrototype>> AllKnowledge
|
||||
);
|
||||
}
|
||||
54
Content.Client/_CP14/Skill/CP14ClientSkillSystem.cs
Normal file
54
Content.Client/_CP14/Skill/CP14ClientSkillSystem.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using Content.Shared._CP14.Skill;
|
||||
using Content.Shared._CP14.Skill.Components;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._CP14.Skill;
|
||||
|
||||
public sealed partial class CP14ClientSkillSystem : CP14SharedSkillSystem
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
public event Action<EntityUid>? OnSkillUpdate;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14SkillStorageComponent, AfterAutoHandleStateEvent>(OnAfterAutoHandleState);
|
||||
}
|
||||
|
||||
private void OnAfterAutoHandleState(Entity<CP14SkillStorageComponent> ent, ref AfterAutoHandleStateEvent args)
|
||||
{
|
||||
OnSkillUpdate?.Invoke(ent.Owner);
|
||||
}
|
||||
|
||||
public void RequestSkillData()
|
||||
{
|
||||
var localPlayer = _playerManager.LocalEntity;
|
||||
|
||||
if (!HasComp<CP14SkillStorageComponent>(localPlayer))
|
||||
return;
|
||||
|
||||
OnSkillUpdate?.Invoke(localPlayer.Value);
|
||||
}
|
||||
|
||||
public void RequestLearnSkill(EntityUid? target, CP14SkillPrototype? skill)
|
||||
{
|
||||
if (skill == null || target == null)
|
||||
return;
|
||||
|
||||
var netEv = new CP14TryLearnSkillMessage(GetNetEntity(target.Value), skill.ID);
|
||||
RaiseNetworkEvent(netEv);
|
||||
|
||||
if (_proto.TryIndex(skill.Tree, out var indexedTree))
|
||||
{
|
||||
_audio.PlayGlobal(indexedTree.LearnSound, target.Value, AudioParams.Default.WithVolume(6f));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
<Control xmlns="https://spacestation14.io" HorizontalExpand="True">
|
||||
<BoxContainer Name="MainContainer"
|
||||
Orientation="Horizontal"
|
||||
HorizontalExpand="True">
|
||||
<Button Name="MainButton"
|
||||
HorizontalExpand="True"
|
||||
VerticalExpand="True"
|
||||
StyleClasses="OpenRight"
|
||||
Margin="0 0 -1 0">
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<BoxContainer Orientation="Vertical"
|
||||
VerticalExpand="True"
|
||||
HorizontalExpand="True"
|
||||
Margin="-5 0 0 0">
|
||||
<Label Name="SkillTreeLabel" />
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</Button>
|
||||
<PanelContainer Name="ColorPanel"
|
||||
VerticalExpand="True"
|
||||
SetWidth="7"
|
||||
Margin="0 1 0 0" />
|
||||
</BoxContainer>
|
||||
</Control>
|
||||
@@ -0,0 +1,22 @@
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client._CP14.Skill.Ui;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CP14SkillTreeButtonControl : Control
|
||||
{
|
||||
public event Action? OnPressed;
|
||||
|
||||
public CP14SkillTreeButtonControl(Color color, string label)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
ColorPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = color };
|
||||
SkillTreeLabel.Text = label;
|
||||
|
||||
MainButton.OnPressed += args => OnPressed?.Invoke();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<ui:CP14SkillTreeGraphControl
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:controls="clr-namespace:Content.Client._CP14.Skill.Ui"
|
||||
xmlns:ui="clr-namespace:Content.Client._CP14.Skill.Ui"
|
||||
HorizontalExpand="True"
|
||||
VerticalExpand="True"
|
||||
MouseFilter="Stop"/>
|
||||
218
Content.Client/_CP14/Skill/Ui/CP14SkillTreeGraphControl.xaml.cs
Normal file
218
Content.Client/_CP14/Skill/Ui/CP14SkillTreeGraphControl.xaml.cs
Normal file
@@ -0,0 +1,218 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Shared._CP14.Skill;
|
||||
using Content.Shared._CP14.Skill.Components;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Input;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._CP14.Skill.Ui;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CP14SkillTreeGraphControl : BoxContainer
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
private readonly CP14SharedSkillSystem _skillSystem;
|
||||
|
||||
private Entity<CP14SkillStorageComponent>? _player;
|
||||
|
||||
private IEnumerable<CP14SkillPrototype> _allSkills;
|
||||
|
||||
private CP14SkillPrototype? _hoveredNode;
|
||||
private CP14SkillPrototype? _selectedNode;
|
||||
public CP14SkillTreePrototype? Tree;
|
||||
|
||||
private bool dragging = false;
|
||||
private Vector2 _previousMousePosition = Vector2.Zero;
|
||||
private Vector2 _globalOffset = new (60,60);
|
||||
|
||||
private const float GridSize = 25f;
|
||||
|
||||
public event Action<CP14SkillPrototype?>? OnNodeSelected;
|
||||
public event Action<Vector2>? OnOffsetChanged;
|
||||
|
||||
public CP14SkillTreeGraphControl()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
_skillSystem = _entManager.System<CP14SharedSkillSystem>();
|
||||
|
||||
_allSkills = _proto.EnumeratePrototypes<CP14SkillPrototype>();
|
||||
_proto.PrototypesReloaded += _ => _allSkills = _proto.EnumeratePrototypes<CP14SkillPrototype>().OrderBy(skill => _skillSystem.GetSkillName(skill)).ToList();
|
||||
OnOffsetChanged?.Invoke(_globalOffset);
|
||||
}
|
||||
|
||||
public void UpdateState(Entity<CP14SkillStorageComponent>? player)
|
||||
{
|
||||
_player = player;
|
||||
OnOffsetChanged?.Invoke(_globalOffset);
|
||||
}
|
||||
|
||||
protected override void KeyBindDown(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
base.KeyBindDown(args);
|
||||
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
if (args.Function == EngineKeyFunctions.UIClick)
|
||||
{
|
||||
dragging = true;
|
||||
|
||||
if (_hoveredNode == null)
|
||||
return;
|
||||
|
||||
OnNodeSelected?.Invoke(_hoveredNode);
|
||||
UserInterfaceManager.ClickSound();
|
||||
_selectedNode = _hoveredNode;
|
||||
}
|
||||
|
||||
if (args.Function == EngineKeyFunctions.UIRightClick)
|
||||
{
|
||||
_globalOffset = new Vector2(60, 60); // Reset offset on right click
|
||||
OnOffsetChanged?.Invoke(_globalOffset);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void KeyBindUp(GUIBoundKeyEventArgs args)
|
||||
{
|
||||
base.KeyBindUp(args);
|
||||
|
||||
if (args.Handled || args.Function != EngineKeyFunctions.UIClick)
|
||||
return;
|
||||
|
||||
dragging = false;
|
||||
}
|
||||
|
||||
protected override void ExitedTree()
|
||||
{
|
||||
base.ExitedTree();
|
||||
|
||||
OnNodeSelected?.Invoke(null);
|
||||
}
|
||||
|
||||
protected override void Draw(DrawingHandleScreen handle)
|
||||
{
|
||||
base.Draw(handle);
|
||||
|
||||
_hoveredNode = null;
|
||||
if (_player == null || Tree == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var cursor = (UserInterfaceManager.MousePositionScaled.Position * UIScale) - GlobalPixelPosition;
|
||||
|
||||
if (dragging)
|
||||
{
|
||||
var delta = cursor - _previousMousePosition;
|
||||
_globalOffset += delta;
|
||||
OnOffsetChanged?.Invoke(_globalOffset);
|
||||
}
|
||||
|
||||
_previousMousePosition = cursor;
|
||||
|
||||
var playerSkills = _player.Value.Comp.LearnedSkills;
|
||||
|
||||
//Draw connection lines
|
||||
foreach (var skill in _allSkills)
|
||||
{
|
||||
if (skill.Tree != Tree)
|
||||
continue;
|
||||
|
||||
var fromPos = skill.SkillUiPosition * GridSize * UIScale + _globalOffset;
|
||||
|
||||
foreach (var prerequisite in skill.Prerequisites)
|
||||
{
|
||||
if (!_proto.TryIndex(prerequisite, out var prerequisiteSkill))
|
||||
continue;
|
||||
|
||||
if (prerequisiteSkill.Tree != Tree)
|
||||
continue;
|
||||
|
||||
var learned = playerSkills.Contains(skill.ID);
|
||||
|
||||
var toPos = prerequisiteSkill.SkillUiPosition * GridSize * UIScale + _globalOffset;
|
||||
var color = learned ? Color.White : Color.FromSrgb(new Color(0.7f, 0.7f, 0.7f));
|
||||
handle.DrawLine(fromPos, toPos, color);
|
||||
}
|
||||
}
|
||||
|
||||
//Draw skill icons over lines
|
||||
foreach (var skill in _allSkills)
|
||||
{
|
||||
if (skill.Tree != Tree)
|
||||
continue;
|
||||
|
||||
//TODO: Not optimized, recalculates every frame. Needs to be calculated on state update and cached.
|
||||
var learned = playerSkills.Contains(skill.ID);
|
||||
var available = _skillSystem.CanLearnSkill(_player.Value, skill.ID);
|
||||
var canBeLearned = learned || skill.Prerequisites.All(prerequisite => playerSkills.Contains(prerequisite));
|
||||
var pos = skill.SkillUiPosition * GridSize * UIScale + _globalOffset;
|
||||
|
||||
// Base skill icon
|
||||
var baseTexture = skill.Icon.Frame0();
|
||||
var baseSize = new Vector2(baseTexture.Width, baseTexture.Height) * 2;
|
||||
var baseQuad = new UIBox2(pos - baseSize / 2, pos + baseSize / 2);
|
||||
|
||||
var hovered = (cursor - pos).LengthSquared() <= (baseSize.X / 2) * (baseSize.X / 2);
|
||||
|
||||
// Frame
|
||||
var frameTexture = Tree.FrameIcon.Frame0();
|
||||
var frameSize = new Vector2(frameTexture.Width, frameTexture.Height) * 2;
|
||||
var frameQuad = new UIBox2(pos - frameSize / 2, pos + frameSize / 2);
|
||||
handle.DrawTextureRect(frameTexture, frameQuad, canBeLearned ? Color.White : Color.FromSrgb(new Color(0.7f, 0.7f, 0.7f)));
|
||||
|
||||
// Selected Skill
|
||||
if (_selectedNode == skill)
|
||||
{
|
||||
var selectedTexture = Tree.SelectedIcon.Frame0();
|
||||
var selectedSize = new Vector2(selectedTexture.Width, selectedTexture.Height) * 2;
|
||||
var selectedQuad = new UIBox2(pos - selectedSize / 2, pos + selectedSize / 2);
|
||||
handle.DrawTextureRect(selectedTexture, selectedQuad, Color.White);
|
||||
}
|
||||
|
||||
// Hovered Skill
|
||||
if (hovered)
|
||||
{
|
||||
_hoveredNode = skill;
|
||||
var hoveredTexture = Tree.HoveredIcon.Frame0();
|
||||
var hoveredSize = new Vector2(hoveredTexture.Width, hoveredTexture.Height) * 2;
|
||||
var hoveredQuad = new UIBox2(pos - hoveredSize / 2, pos + hoveredSize / 2);
|
||||
handle.DrawTextureRect(hoveredTexture, hoveredQuad, Color.White);
|
||||
}
|
||||
|
||||
// Learned Skill
|
||||
if (learned)
|
||||
{
|
||||
var learnedTexture = Tree.LearnedIcon.Frame0();
|
||||
var learnedSize = new Vector2(learnedTexture.Width, learnedTexture.Height) * 2;
|
||||
var learnedQuad = new UIBox2(pos - learnedSize / 2, pos + learnedSize / 2);
|
||||
handle.DrawTextureRect(learnedTexture, learnedQuad, Color.White);
|
||||
}
|
||||
else if (available)
|
||||
{
|
||||
var availableTexture = Tree.AvailableIcon.Frame0();
|
||||
var availableSize = new Vector2(availableTexture.Width, availableTexture.Height) * 2;
|
||||
var availableQuad = new UIBox2(pos - availableSize / 2, pos + availableSize / 2);
|
||||
handle.DrawTextureRect(availableTexture, availableQuad, Color.White);
|
||||
}
|
||||
|
||||
var iconColor = Color.White;
|
||||
if (!learned)
|
||||
iconColor = Color.FromSrgb(new Color(0.7f, 0.7f, 0.7f));
|
||||
if (!canBeLearned && !learned)
|
||||
iconColor = Color.FromSrgb(new Color(0f, 0f, 0f));
|
||||
|
||||
handle.DrawTextureRect(baseTexture, baseQuad, iconColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
using Content.Client._CP14.Knowledge;
|
||||
using Content.Client._CP14.UserInterface.Systems.Knowledge.Windows;
|
||||
using Content.Client.Gameplay;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared.Input;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controllers;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.UserInterface.Systems.Character;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class CP14KnowledgeUIController : UIController, IOnStateEntered<GameplayState>, IOnStateExited<GameplayState>,
|
||||
IOnSystemChanged<ClientCP14KnowledgeSystem>
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[UISystemDependency] private readonly ClientCP14KnowledgeSystem _knowledge = default!;
|
||||
|
||||
private CP14KnowledgeWindow? _window;
|
||||
|
||||
private MenuButton? KnowledgeButton => UIManager.GetActiveUIWidgetOrNull<MenuBar.Widgets.GameTopMenuBar>()?.CP14KnowledgeButton;
|
||||
|
||||
public void OnStateEntered(GameplayState state)
|
||||
{
|
||||
DebugTools.Assert(_window == null);
|
||||
|
||||
_window = UIManager.CreateWindow<CP14KnowledgeWindow>();
|
||||
LayoutContainer.SetAnchorPreset(_window, LayoutContainer.LayoutPreset.CenterTop);
|
||||
|
||||
CommandBinds.Builder
|
||||
.Bind(ContentKeyFunctions.CP14OpenKnowledgeMenu,
|
||||
InputCmdHandler.FromDelegate(_ => ToggleWindow()))
|
||||
.Register<CP14KnowledgeUIController>();
|
||||
}
|
||||
|
||||
public void OnStateExited(GameplayState state)
|
||||
{
|
||||
if (_window != null)
|
||||
{
|
||||
_window.Dispose();
|
||||
_window = null;
|
||||
}
|
||||
|
||||
CommandBinds.Unregister<CP14KnowledgeUIController>();
|
||||
}
|
||||
|
||||
public void OnSystemLoaded(ClientCP14KnowledgeSystem system)
|
||||
{
|
||||
system.OnKnowledgeUpdate += KnowledgeUpdated;
|
||||
_player.LocalPlayerDetached += CharacterDetached;
|
||||
}
|
||||
|
||||
public void OnSystemUnloaded(ClientCP14KnowledgeSystem system)
|
||||
{
|
||||
system.OnKnowledgeUpdate -= KnowledgeUpdated;
|
||||
_player.LocalPlayerDetached -= CharacterDetached;
|
||||
}
|
||||
|
||||
public void UnloadButton()
|
||||
{
|
||||
if (KnowledgeButton is null)
|
||||
return;
|
||||
|
||||
KnowledgeButton.OnPressed -= KnowledgeButtonPressed;
|
||||
}
|
||||
|
||||
public void LoadButton()
|
||||
{
|
||||
if (KnowledgeButton is null)
|
||||
return;
|
||||
|
||||
KnowledgeButton.OnPressed += KnowledgeButtonPressed;
|
||||
|
||||
if (_window is null)
|
||||
return;
|
||||
|
||||
_window.OnClose += DeactivateButton;
|
||||
_window.OnOpen += ActivateButton;
|
||||
}
|
||||
|
||||
private void DeactivateButton()
|
||||
{
|
||||
KnowledgeButton!.Pressed = false;
|
||||
}
|
||||
|
||||
private void ActivateButton()
|
||||
{
|
||||
KnowledgeButton!.Pressed = true;
|
||||
}
|
||||
|
||||
private void KnowledgeUpdated(ClientCP14KnowledgeSystem.KnowledgeData data)
|
||||
{
|
||||
if (_window is null)
|
||||
return;
|
||||
|
||||
_window.KnowledgeContent.RemoveAllChildren();
|
||||
|
||||
var (entity, allKnowledge) = data;
|
||||
|
||||
foreach (var knowledge in allKnowledge)
|
||||
{
|
||||
if (!_proto.TryIndex(knowledge, out var indexedKnowledge))
|
||||
continue;
|
||||
|
||||
var knowledgeButton = new Button()
|
||||
{
|
||||
Access = AccessLevel.Public,
|
||||
Text = Loc.GetString(indexedKnowledge.Name),
|
||||
ToolTip = Loc.GetString(indexedKnowledge.Desc),
|
||||
TextAlign = Label.AlignMode.Center,
|
||||
};
|
||||
|
||||
_window.KnowledgeContent.AddChild(knowledgeButton);
|
||||
}
|
||||
}
|
||||
|
||||
private void CharacterDetached(EntityUid uid)
|
||||
{
|
||||
CloseWindow();
|
||||
}
|
||||
|
||||
private void KnowledgeButtonPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
ToggleWindow();
|
||||
}
|
||||
|
||||
private void CloseWindow()
|
||||
{
|
||||
_window?.Close();
|
||||
}
|
||||
|
||||
private void ToggleWindow()
|
||||
{
|
||||
if (_window == null)
|
||||
return;
|
||||
|
||||
if (KnowledgeButton != null)
|
||||
{
|
||||
KnowledgeButton.SetClickPressed(!_window.IsOpen);
|
||||
}
|
||||
|
||||
if (_window.IsOpen)
|
||||
{
|
||||
CloseWindow();
|
||||
}
|
||||
else
|
||||
{
|
||||
_knowledge.RequestKnowledgeInfo();
|
||||
_window.Open();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<windows:CP14KnowledgeWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:cc="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
xmlns:windows="clr-namespace:Content.Client._CP14.UserInterface.Systems.Knowledge.Windows"
|
||||
Title="{Loc 'cp14-knowledge-info-title'}"
|
||||
MinWidth="400"
|
||||
MinHeight="200">
|
||||
<ScrollContainer>
|
||||
<BoxContainer Name="KnowledgeContent" Margin="5" Access="Public" Orientation="Vertical">
|
||||
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
</windows:CP14KnowledgeWindow>
|
||||
@@ -0,0 +1,249 @@
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Client._CP14.Skill;
|
||||
using Content.Client._CP14.Skill.Ui;
|
||||
using Content.Client._CP14.UserInterface.Systems.Skill.Window;
|
||||
using Content.Client.Gameplay;
|
||||
using Content.Client.UserInterface.Controls;
|
||||
using Content.Shared._CP14.Skill.Components;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared.Input;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.Player;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controllers;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.Utility;
|
||||
using Robust.Shared.Input.Binding;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.UserInterface.Systems.Character;
|
||||
|
||||
[UsedImplicitly]
|
||||
public sealed class CP14SkillUIController : UIController, IOnStateEntered<GameplayState>, IOnStateExited<GameplayState>,
|
||||
IOnSystemChanged<CP14ClientSkillSystem>
|
||||
{
|
||||
[Dependency] private readonly IPlayerManager _player = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[UISystemDependency] private readonly CP14ClientSkillSystem _skill = default!;
|
||||
|
||||
private CP14SkillWindow? _window;
|
||||
private CP14SkillPrototype? _selectedSkill;
|
||||
|
||||
private MenuButton? SkillButton => UIManager.GetActiveUIWidgetOrNull<MenuBar.Widgets.GameTopMenuBar>()?.CP14SkillButton;
|
||||
|
||||
public void OnStateEntered(GameplayState state)
|
||||
{
|
||||
DebugTools.Assert(_window == null);
|
||||
|
||||
_window = UIManager.CreateWindow<CP14SkillWindow>();
|
||||
LayoutContainer.SetAnchorPreset(_window, LayoutContainer.LayoutPreset.CenterTop);
|
||||
|
||||
CommandBinds.Builder
|
||||
.Bind(ContentKeyFunctions.CP14OpenSkillMenu,
|
||||
InputCmdHandler.FromDelegate(_ => ToggleWindow()))
|
||||
.Register<CP14SkillUIController>();
|
||||
|
||||
_window.LearnButton.OnPressed += _ => _skill.RequestLearnSkill(_player.LocalEntity, _selectedSkill);
|
||||
_window.GraphControl.OnNodeSelected += SelectNode;
|
||||
_window.GraphControl.OnOffsetChanged += offset =>
|
||||
{
|
||||
_window.ParallaxBackground.Offset = -offset * 0.25f + new Vector2(1000,1000); //hardcoding is bad
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public void OnStateExited(GameplayState state)
|
||||
{
|
||||
if (_window != null)
|
||||
{
|
||||
_window.GraphControl.OnNodeSelected -= SelectNode;
|
||||
|
||||
_window.Dispose();
|
||||
_window = null;
|
||||
}
|
||||
|
||||
CommandBinds.Unregister<CP14SkillUIController>();
|
||||
}
|
||||
|
||||
public void OnSystemLoaded(CP14ClientSkillSystem system)
|
||||
{
|
||||
system.OnSkillUpdate += UpdateState;
|
||||
_player.LocalPlayerDetached += CharacterDetached;
|
||||
}
|
||||
|
||||
public void OnSystemUnloaded(CP14ClientSkillSystem system)
|
||||
{
|
||||
system.OnSkillUpdate -= UpdateState;
|
||||
_player.LocalPlayerDetached -= CharacterDetached;
|
||||
}
|
||||
|
||||
public void UnloadButton()
|
||||
{
|
||||
if (SkillButton is null)
|
||||
return;
|
||||
|
||||
SkillButton.OnPressed -= SkillButtonPressed;
|
||||
}
|
||||
|
||||
public void LoadButton()
|
||||
{
|
||||
if (SkillButton is null)
|
||||
return;
|
||||
|
||||
SkillButton.OnPressed += SkillButtonPressed;
|
||||
|
||||
if (_window is null)
|
||||
return;
|
||||
|
||||
_window.OnClose += DeactivateButton;
|
||||
_window.OnOpen += ActivateButton;
|
||||
}
|
||||
|
||||
private void DeactivateButton()
|
||||
{
|
||||
SkillButton!.Pressed = false;
|
||||
}
|
||||
|
||||
private void ActivateButton()
|
||||
{
|
||||
SkillButton!.Pressed = true;
|
||||
}
|
||||
|
||||
private void SelectNode(CP14SkillPrototype? skill)
|
||||
{
|
||||
if (_window is null)
|
||||
return;
|
||||
|
||||
if (_player.LocalEntity == null)
|
||||
return;
|
||||
|
||||
_selectedSkill = skill;
|
||||
|
||||
if (skill == null)
|
||||
{
|
||||
_window.SkillName.Text = string.Empty;
|
||||
_window.SkillDescription.Text = string.Empty;
|
||||
_window.SkillView.Texture = null;
|
||||
_window.LearnButton.Disabled = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_window.SkillName.Text = _skill.GetSkillName(skill);
|
||||
_window.SkillDescription.SetMessage(GetSkillDescription(skill));
|
||||
_window.SkillView.Texture = skill.Icon.Frame0();
|
||||
_window.LearnButton.Disabled = !_skill.CanLearnSkill(_player.LocalEntity.Value, skill);
|
||||
_window.SkillCost.Text = skill.LearnCost.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
private FormattedMessage GetSkillDescription(CP14SkillPrototype skill)
|
||||
{
|
||||
var msg = new FormattedMessage();
|
||||
|
||||
//Description
|
||||
msg.TryAddMarkup(_skill.GetSkillDescription(skill) + "\n", out _);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
private void UpdateState(EntityUid player)
|
||||
{
|
||||
if (_window is null)
|
||||
return;
|
||||
|
||||
if (!EntityManager.TryGetComponent<CP14SkillStorageComponent>(player, out var storage))
|
||||
return;
|
||||
|
||||
_window.GraphControl.UpdateState((player, storage));
|
||||
|
||||
// Reselect for update state
|
||||
SelectNode(_selectedSkill);
|
||||
|
||||
//If tree not selected, select the first one
|
||||
if (_window.GraphControl.Tree == null && storage.Progress.Count > 0)
|
||||
{
|
||||
var firstTree = storage.Progress.First().Key;
|
||||
|
||||
if (_proto.TryIndex(firstTree, out var indexedTree))
|
||||
{
|
||||
SelectTree(indexedTree, storage); // Set the first tree from the player's progress
|
||||
}
|
||||
}
|
||||
|
||||
// Update the experience points for the selected tree
|
||||
var playerProgress = storage.Progress;
|
||||
if (_window.GraphControl.Tree is not null && playerProgress.TryGetValue(_window.GraphControl.Tree, out var skillpoint))
|
||||
{
|
||||
_window.ExpPointLabel.Text = skillpoint.ToString();
|
||||
}
|
||||
|
||||
_window.LevelLabel.Text = $"{storage.SkillsSumExperience}/{storage.ExperienceMaxCap}";
|
||||
|
||||
_window.TreeTabsContainer.RemoveAllChildren();
|
||||
foreach (var (tree, progress) in storage.Progress)
|
||||
{
|
||||
if (!_proto.TryIndex(tree, out var indexedTree))
|
||||
continue;
|
||||
|
||||
var treeButton2 = new CP14SkillTreeButtonControl(indexedTree.Color, Loc.GetString(indexedTree.Name));
|
||||
treeButton2.ToolTip = Loc.GetString(indexedTree.Desc ?? string.Empty);
|
||||
treeButton2.OnPressed += () =>
|
||||
{
|
||||
SelectTree(indexedTree, storage);
|
||||
};
|
||||
|
||||
_window.TreeTabsContainer.AddChild(treeButton2);
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectTree(CP14SkillTreePrototype tree, CP14SkillStorageComponent storage)
|
||||
{
|
||||
if (_window == null)
|
||||
return;
|
||||
|
||||
_window.GraphControl.Tree = tree;
|
||||
_window.ParallaxBackground.ParallaxPrototype = tree.Parallax;
|
||||
_window.TreeName.Text = Loc.GetString(tree.Name);
|
||||
|
||||
var playerProgress = storage.Progress;
|
||||
_window.ExpPointLabel.Text = playerProgress.TryGetValue(tree, out var skillpoint) ? skillpoint.ToString() : "0";
|
||||
}
|
||||
|
||||
private void CharacterDetached(EntityUid uid)
|
||||
{
|
||||
CloseWindow();
|
||||
}
|
||||
|
||||
private void SkillButtonPressed(BaseButton.ButtonEventArgs args)
|
||||
{
|
||||
ToggleWindow();
|
||||
}
|
||||
|
||||
private void CloseWindow()
|
||||
{
|
||||
_window?.Close();
|
||||
}
|
||||
|
||||
private void ToggleWindow()
|
||||
{
|
||||
if (_window == null)
|
||||
return;
|
||||
|
||||
if (SkillButton != null)
|
||||
{
|
||||
SkillButton.SetClickPressed(!_window.IsOpen);
|
||||
}
|
||||
|
||||
if (_window.IsOpen)
|
||||
{
|
||||
CloseWindow();
|
||||
}
|
||||
else
|
||||
{
|
||||
_skill.RequestSkillData();
|
||||
_window.Open();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<window:CP14SkillWindow
|
||||
xmlns="https://spacestation14.io"
|
||||
xmlns:window="clr-namespace:Content.Client._CP14.UserInterface.Systems.Skill.Window"
|
||||
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls"
|
||||
xmlns:parallax="clr-namespace:Content.Client.Parallax"
|
||||
xmlns:ui1="clr-namespace:Content.Client._CP14.Skill.Ui"
|
||||
Title="{Loc 'cp14-skill-info-title'}"
|
||||
MinSize="700 350"
|
||||
SetSize="980 550">
|
||||
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" VerticalExpand="True">
|
||||
|
||||
<!-- Selected Skill -->
|
||||
<BoxContainer Margin="10 10 10 10" MaxWidth="240" SetWidth="240" Orientation="Vertical"
|
||||
HorizontalExpand="False" VerticalExpand="True">
|
||||
<!-- Skill View -->
|
||||
<PanelContainer Name="BackPanel" HorizontalAlignment="Center">
|
||||
<PanelContainer.PanelOverride>
|
||||
<graphics:StyleBoxTexture Modulate="#1B1B1E" PatchMarginBottom="10" PatchMarginLeft="10"
|
||||
PatchMarginRight="10" PatchMarginTop="10" />
|
||||
</PanelContainer.PanelOverride>
|
||||
<BoxContainer HorizontalExpand="True" VerticalExpand="True" >
|
||||
<TextureRect Stretch="Scale" Name="SkillView" SetSize="64 64" HorizontalAlignment="Center" VerticalAlignment="Center" MinSize="64 64"
|
||||
HorizontalExpand="True" VerticalExpand="True" Access="Public"/>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
<customControls:HSeparator StyleClasses="HighDivider" Margin="0 15 0 10" />
|
||||
<!-- Skill Data -->
|
||||
<BoxContainer Name="NodeViewContainer" Orientation="Vertical" VerticalExpand="True">
|
||||
<ScrollContainer HScrollEnabled="False" HorizontalExpand="True" VerticalExpand="True">
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="False" VerticalExpand="True">
|
||||
<BoxContainer Name="InfoContainer" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
|
||||
<BoxContainer HorizontalExpand="True">
|
||||
<Label Name="SkillName" Access="Public" StyleClasses="LabelHeadingBigger" VAlign="Center"
|
||||
HorizontalExpand="True" HorizontalAlignment="Center" />
|
||||
</BoxContainer>
|
||||
<!-- Skill Cost -->
|
||||
<BoxContainer HorizontalExpand="True">
|
||||
<RichTextLabel HorizontalExpand="True" Access="Public" Text="{Loc 'cp14-skill-menu-learncost'}" Margin="0 10 0 10" />
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Left" TextureScale="2, 2" TexturePath="/Textures/_CP14/Interface/Skills/skillpoint.png"/>
|
||||
<RichTextLabel Name="SkillCost" Access="Public" Text="0"/>
|
||||
</BoxContainer>
|
||||
<!-- Skill Description -->
|
||||
<BoxContainer HorizontalExpand="True">
|
||||
<RichTextLabel Name="SkillDescription" HorizontalExpand="True" Access="Public"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
<Control MinHeight="5"/>
|
||||
<!-- Skill Buttons -->
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<Button Name="LearnButton" Text="{Loc 'cp14-skill-menu-learn-button'}" StyleClasses="OpenRight" HorizontalExpand="True" MinHeight="35" Access="Public"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<customControls:VSeparator StyleClasses="LowDivider" />
|
||||
|
||||
<!-- Skills Tree -->
|
||||
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
|
||||
<BoxContainer HorizontalExpand="True">
|
||||
<Label Name="TreeName" Access="Public" StyleClasses="LabelHeadingBigger" VAlign="Center"
|
||||
HorizontalExpand="True" HorizontalAlignment="Center" />
|
||||
</BoxContainer>
|
||||
<PanelContainer Margin="10 10 10 10" HorizontalExpand="True" VerticalExpand="True" RectClipContent="True">
|
||||
<parallax:ParallaxControl Name="ParallaxBackground" ScaleX="4" ScaleY="4" Access="Public" SpeedX="10" SpeedY="5"/>
|
||||
<BoxContainer Margin="10 10 10 10" Orientation="Horizontal" HorizontalExpand="True" VerticalExpand="True">
|
||||
<ui1:CP14SkillTreeGraphControl Name="GraphControl" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Access="Public"/>
|
||||
</BoxContainer>
|
||||
<!-- Tree Tabs -->
|
||||
<BoxContainer Margin="10 10 10 10" VerticalAlignment="Top" HorizontalAlignment="Right" Orientation="Vertical" VerticalExpand="True">
|
||||
<BoxContainer Name="TreeTabsContainer" Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Access="Public"/>
|
||||
</BoxContainer>
|
||||
<!-- Experience Data -->
|
||||
<BoxContainer Margin="10 10 10 10" VerticalAlignment="Bottom" HorizontalAlignment="Center" Orientation="Horizontal" VerticalExpand="True">
|
||||
<RichTextLabel VerticalAlignment="Center" HorizontalAlignment="Left" Text="{Loc 'cp14-skill-menu-skillpoints'}" StyleClasses="LabelKeyText"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2, 2" TexturePath="/Textures/_CP14/Interface/Skills/skillpoint.png"/>
|
||||
<RichTextLabel Margin="0 0 20 0" Name="ExpPointLabel" VerticalAlignment="Center" HorizontalAlignment="Left" Text="0" StyleClasses="LabelKeyText" Access="Public"/>
|
||||
|
||||
<RichTextLabel VerticalAlignment="Center" HorizontalAlignment="Left" Text="{Loc 'cp14-skill-menu-level'}" StyleClasses="LabelKeyText"/>
|
||||
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2, 2" TexturePath="/Textures/_CP14/Interface/Skills/skillpoint.png"/>
|
||||
<RichTextLabel Margin="0 0 0 0" Name="LevelLabel" VerticalAlignment="Center" HorizontalAlignment="Left" Text="0" StyleClasses="LabelKeyText" Access="Public"/>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</window:CP14SkillWindow>
|
||||
@@ -2,12 +2,12 @@ using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
|
||||
namespace Content.Client._CP14.UserInterface.Systems.Knowledge.Windows;
|
||||
namespace Content.Client._CP14.UserInterface.Systems.Skill.Window;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CP14KnowledgeWindow : DefaultWindow
|
||||
public sealed partial class CP14SkillWindow : DefaultWindow
|
||||
{
|
||||
public CP14KnowledgeWindow()
|
||||
public CP14SkillWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Shared._CP14.Farming;
|
||||
using Content.Shared._CP14.Knowledge;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||
|
||||
@@ -81,6 +81,9 @@ public sealed partial class CP14DemiplaneSystem
|
||||
|
||||
while (query.MoveNext(out var uid, out var stabilizer, out var xform))
|
||||
{
|
||||
if (!stabilizer.Enabled)
|
||||
continue;
|
||||
|
||||
if (TryTeleportOutDemiplane(demiplane, uid))
|
||||
{
|
||||
if (!safe)
|
||||
|
||||
@@ -1,71 +0,0 @@
|
||||
using Content.Shared._CP14.Knowledge.Components;
|
||||
using Content.Shared._CP14.Knowledge.Prototypes;
|
||||
using Content.Shared.Administration;
|
||||
using Content.Shared.Administration.Managers;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Knowledge;
|
||||
|
||||
// TODO: Add UI
|
||||
public sealed class CP14KnowledgeAdminUtilitiesSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ISharedAdminManager _admin = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly CP14KnowledgeSystem _knowledge = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14KnowledgeStorageComponent, GetVerbsEvent<Verb>>(AddKnowledgeAdminVerb);
|
||||
}
|
||||
|
||||
private void AddKnowledgeAdminVerb(Entity<CP14KnowledgeStorageComponent> entity, ref GetVerbsEvent<Verb> args)
|
||||
{
|
||||
if (!_admin.HasAdminFlag(args.User, AdminFlags.Admin))
|
||||
return;
|
||||
|
||||
// Remove knowledge
|
||||
foreach (var knowledge in entity.Comp.Knowledge)
|
||||
{
|
||||
if (!_prototype.TryIndex(knowledge, out var indexedKnowledge))
|
||||
continue;
|
||||
|
||||
args.Verbs.Add(new Verb
|
||||
{
|
||||
Text = $"{Loc.GetString(indexedKnowledge.Name)}",
|
||||
Message = Loc.GetString(indexedKnowledge.Desc),
|
||||
Category = VerbCategory.CP14KnowledgeRemove,
|
||||
Act = () =>
|
||||
{
|
||||
_knowledge.TryRemove(entity.Owner, knowledge);
|
||||
},
|
||||
Impact = LogImpact.High,
|
||||
});
|
||||
}
|
||||
|
||||
// Add knowledge
|
||||
foreach (var knowledge in _prototype.EnumeratePrototypes<CP14KnowledgePrototype>())
|
||||
{
|
||||
// An entity with CP14AllKnowingComponent can't be taught anything,
|
||||
// it already knows everything
|
||||
if (_knowledge.HasKnowledge(entity.Owner, knowledge.ID))
|
||||
continue;
|
||||
|
||||
args.Verbs.Add(new Verb
|
||||
{
|
||||
Text = $"{Loc.GetString(knowledge.Name)}",
|
||||
Message = Loc.GetString(knowledge.Desc),
|
||||
Category = VerbCategory.CP14KnowledgeAdd,
|
||||
Act = () =>
|
||||
{
|
||||
_knowledge.TryAdd(entity.Owner, knowledge, true);
|
||||
},
|
||||
Impact = LogImpact.High,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
using System.Text;
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.Mind;
|
||||
using Content.Shared._CP14.Knowledge;
|
||||
using Content.Shared._CP14.Knowledge.Components;
|
||||
using Content.Shared._CP14.Knowledge.Events;
|
||||
using Content.Shared._CP14.Knowledge.Prototypes;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Chat;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Knowledge;
|
||||
|
||||
public sealed class CP14KnowledgeSystem : SharedCP14KnowledgeSystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly IChatManager _chat = default!;
|
||||
[Dependency] private readonly MindSystem _mind = default!;
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14AutoAddKnowledgeComponent, MapInitEvent>(AutoAddSkill);
|
||||
SubscribeLocalEvent<CP14KnowledgeStorageComponent, CP14KnowledgeLearnDoAfterEvent>(KnowledgeLearnedEvent);
|
||||
SubscribeLocalEvent<CP14KnowledgeLearningSourceComponent, GetVerbsEvent<Verb>>(AddKnowledgeLearningVerb);
|
||||
|
||||
SubscribeNetworkEvent<CP14RequestKnowledgeInfoEvent>(OnRequestKnowledgeInfoEvent);
|
||||
}
|
||||
|
||||
private void AddKnowledgeLearningVerb(Entity<CP14KnowledgeLearningSourceComponent> ent, ref GetVerbsEvent<Verb> args)
|
||||
{
|
||||
var user = args.User;
|
||||
foreach (var knowledge in ent.Comp.Knowledge)
|
||||
{
|
||||
if (!_prototype.TryIndex(knowledge, out var indexedKnowledge))
|
||||
continue;
|
||||
|
||||
args.Verbs.Add(new Verb
|
||||
{
|
||||
Text = $"{Loc.GetString(indexedKnowledge.Name)}",
|
||||
Message = Loc.GetString(indexedKnowledge.Desc),
|
||||
Category = VerbCategory.CP14KnowledgeLearn,
|
||||
Act = () =>
|
||||
{
|
||||
_doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager,
|
||||
user,
|
||||
ent.Comp.DoAfter,
|
||||
new CP14KnowledgeLearnDoAfterEvent { Knowledge = knowledge },
|
||||
user,
|
||||
ent,
|
||||
ent)
|
||||
{
|
||||
BreakOnDamage = true,
|
||||
BreakOnMove = true,
|
||||
});
|
||||
},
|
||||
Disabled = HasKnowledge(user, knowledge),
|
||||
Impact = LogImpact.Medium,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void KnowledgeLearnedEvent(Entity<CP14KnowledgeStorageComponent> ent, ref CP14KnowledgeLearnDoAfterEvent args)
|
||||
{
|
||||
if (args.Cancelled || args.Handled)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
TryAdd(ent.Owner, args.Knowledge);
|
||||
}
|
||||
|
||||
private void AutoAddSkill(Entity<CP14AutoAddKnowledgeComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
foreach (var knowledge in ent.Comp.Knowledge)
|
||||
{
|
||||
TryAdd(ent.Owner, knowledge);
|
||||
}
|
||||
|
||||
RemComp(ent, ent.Comp);
|
||||
}
|
||||
|
||||
public bool TryAdd(Entity<CP14KnowledgeStorageComponent?> entity, ProtoId<CP14KnowledgePrototype> knowledgeId, bool force = false, bool silent = false)
|
||||
{
|
||||
if (!Resolve(entity, ref entity.Comp, false))
|
||||
return false;
|
||||
|
||||
if (HasKnowledge(entity, knowledgeId))
|
||||
return false;
|
||||
|
||||
if (!_prototype.TryIndex(knowledgeId, out var knowledge))
|
||||
return false;
|
||||
|
||||
MindComponent? mindComponent;
|
||||
|
||||
foreach (var dependencyKnowledgeId in knowledge.Dependencies)
|
||||
{
|
||||
if (!_prototype.TryIndex(dependencyKnowledgeId, out var dependencyKnowledge))
|
||||
return false;
|
||||
|
||||
// If we teach by force - we automatically teach all the basics that are necessary for that skill.
|
||||
if (force && !TryAdd(entity, dependencyKnowledge, true))
|
||||
return false;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(Loc.GetString("cp14-cant-learn-knowledge-dependencies", ("target", Loc.GetString(knowledge.Desc))));
|
||||
|
||||
// We cant learnt
|
||||
if (HasKnowledge(entity, dependencyKnowledge))
|
||||
continue;
|
||||
|
||||
sb.Append($"\n- {Loc.GetString(dependencyKnowledge.Desc)}");
|
||||
|
||||
if (silent)
|
||||
return false;
|
||||
|
||||
if (!_mind.TryGetMind(entity, out _, out mindComponent) || mindComponent.Session is null)
|
||||
return false;
|
||||
|
||||
var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", sb.ToString()));
|
||||
_chat.ChatMessageToOne(
|
||||
ChatChannel.Server,
|
||||
sb.ToString(),
|
||||
wrappedMessage,
|
||||
default,
|
||||
false,
|
||||
mindComponent.Session.Channel);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!entity.Comp.Knowledge.Add(knowledgeId))
|
||||
return false;
|
||||
|
||||
_adminLogger.Add(LogType.Mind, LogImpact.Medium, $"{EntityManager.ToPrettyString(entity):player} learned new knowledge: {Loc.GetString(knowledge.Name)}");
|
||||
|
||||
// TODO: coding on a sleepy head is a bad idea. Remove duplicate variables. >:(
|
||||
if (silent)
|
||||
return true;
|
||||
|
||||
if (!_mind.TryGetMind(entity, out _, out mindComponent) || mindComponent.Session is null)
|
||||
return false;
|
||||
|
||||
var message = Loc.GetString("cp14-learned-new-knowledge", ("name", Loc.GetString(knowledge.Name)));
|
||||
var wrappedMessage2 = Loc.GetString("chat-manager-server-wrap-message", ("message", message));
|
||||
|
||||
_chat.ChatMessageToOne(
|
||||
ChatChannel.Server,
|
||||
message,
|
||||
wrappedMessage2,
|
||||
default,
|
||||
false,
|
||||
mindComponent.Session.Channel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryRemove(Entity<CP14KnowledgeStorageComponent?> entity, ProtoId<CP14KnowledgePrototype> proto, bool silent = false)
|
||||
{
|
||||
if (!Resolve(entity, ref entity.Comp, false))
|
||||
return false;
|
||||
|
||||
if (!entity.Comp.Knowledge.Contains(proto))
|
||||
return false;
|
||||
|
||||
if (!_prototype.TryIndex(proto, out var indexedKnowledge))
|
||||
return false;
|
||||
|
||||
if (!entity.Comp.Knowledge.Remove(proto))
|
||||
return false;
|
||||
|
||||
_adminLogger.Add(LogType.Mind, LogImpact.Medium, $"{EntityManager.ToPrettyString(entity):player} forgot knowledge: {Loc.GetString(indexedKnowledge.Name)}");
|
||||
|
||||
if (silent)
|
||||
return true;
|
||||
|
||||
if (!_mind.TryGetMind(entity, out _, out var mindComp) || mindComp.Session is null)
|
||||
return true;
|
||||
|
||||
var message = Loc.GetString("cp14-forgot-knowledge", ("name", Loc.GetString(indexedKnowledge.Name)));
|
||||
var wrappedMessage = Loc.GetString("chat-manager-server-wrap-message", ("message", message));
|
||||
|
||||
_chat.ChatMessageToOne(
|
||||
ChatChannel.Server,
|
||||
message,
|
||||
wrappedMessage,
|
||||
default,
|
||||
false,
|
||||
mindComp.Session.Channel);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnRequestKnowledgeInfoEvent(CP14RequestKnowledgeInfoEvent msg, EntitySessionEventArgs args)
|
||||
{
|
||||
if (!args.SenderSession.AttachedEntity.HasValue || args.SenderSession.AttachedEntity != GetEntity(msg.NetEntity))
|
||||
return;
|
||||
|
||||
var entity = args.SenderSession.AttachedEntity.Value;
|
||||
|
||||
if (!TryComp<CP14KnowledgeStorageComponent>(entity, out var knowledgeComp))
|
||||
return;
|
||||
|
||||
RaiseNetworkEvent(new CP14KnowledgeInfoEvent(GetNetEntity(entity),knowledgeComp.Knowledge), args.SenderSession);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
using Content.Shared._CP14.Knowledge.Prototypes;
|
||||
using Content.Shared.Roles;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Knowledge.Specials;
|
||||
|
||||
/// <summary>
|
||||
/// a component that can be hung on an entity to immediately teach it some skills
|
||||
/// </summary>
|
||||
[UsedImplicitly]
|
||||
public sealed partial class CP14AddKnowledgeSpecial : JobSpecial
|
||||
{
|
||||
[DataField(required: true), ViewVariables(VVAccess.ReadOnly)]
|
||||
public List<ProtoId<CP14KnowledgePrototype>> Knowledge = [];
|
||||
|
||||
public override void AfterEquip(EntityUid mob)
|
||||
{
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
var knowledgeSystem = entMan.System<CP14KnowledgeSystem>();
|
||||
|
||||
foreach (var knowledge in Knowledge)
|
||||
{
|
||||
knowledgeSystem.TryAdd(mob, knowledge, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.MagicSpell;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14AutoLearnActionComponent : Component
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public HashSet<EntProtoId> Actions = new();
|
||||
}
|
||||
@@ -45,17 +45,6 @@ public sealed partial class CP14MagicSystem : CP14SharedMagicSystem
|
||||
SubscribeLocalEvent<CP14MagicEffectManaCostComponent, CP14MagicEffectConsumeResourceEvent>(OnManaConsume);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectRequiredMusicToolComponent, CP14CastMagicEffectAttemptEvent>(OnMusicCheck);
|
||||
|
||||
SubscribeLocalEvent<CP14AutoLearnActionComponent, MapInitEvent>(OnAutoLearnAction);
|
||||
}
|
||||
|
||||
private void OnAutoLearnAction(Entity<CP14AutoLearnActionComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
foreach (var action in ent.Comp.Actions)
|
||||
{
|
||||
_action.AddAction(ent, action);
|
||||
}
|
||||
RemCompDeferred<CP14AutoLearnActionComponent>(ent);
|
||||
}
|
||||
|
||||
private void OnProjectileHit(Entity<CP14SpellEffectOnHitComponent> ent, ref ThrowDoHitEvent args)
|
||||
|
||||
24
Content.Server/_CP14/Skill/CP14SkillSystem.cs
Normal file
24
Content.Server/_CP14/Skill/CP14SkillSystem.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Content.Shared._CP14.Skill;
|
||||
using Content.Shared._CP14.Skill.Components;
|
||||
|
||||
namespace Content.Server._CP14.Skill;
|
||||
|
||||
public sealed partial class CP14SkillSystem : CP14SharedSkillSystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeNetworkEvent<CP14TryLearnSkillMessage>(OnClientRequestLearnSkill);
|
||||
}
|
||||
|
||||
private void OnClientRequestLearnSkill(CP14TryLearnSkillMessage ev, EntitySessionEventArgs args)
|
||||
{
|
||||
var entity = GetEntity(ev.Entity);
|
||||
|
||||
if (args.SenderSession.AttachedEntity != entity)
|
||||
return;
|
||||
|
||||
TryLearnSkill(entity, ev.Skill);
|
||||
}
|
||||
}
|
||||
@@ -30,13 +30,22 @@ public sealed partial class CP14WorkbenchSystem
|
||||
if (!_proto.TryIndex(recipeId, out var indexedRecipe))
|
||||
continue;
|
||||
|
||||
//if (indexedRecipe.KnowledgeRequired is not null)
|
||||
//{
|
||||
// if (!_knowledge.HasKnowledge(user, indexedRecipe.KnowledgeRequired.Value))
|
||||
// continue;
|
||||
//}
|
||||
var canCraft = true;
|
||||
var hidden = false;
|
||||
|
||||
var entry = new CP14WorkbenchUiRecipesEntry(recipeId, CanCraftRecipe(indexedRecipe, placedEntities, user));
|
||||
foreach (var requirement in indexedRecipe.Requirements)
|
||||
{
|
||||
if (!requirement.CheckRequirement(EntityManager, _proto, placedEntities, user, indexedRecipe))
|
||||
{
|
||||
canCraft = false;
|
||||
hidden = requirement.HideRecipe;
|
||||
}
|
||||
}
|
||||
|
||||
if (hidden)
|
||||
continue;
|
||||
|
||||
var entry = new CP14WorkbenchUiRecipesEntry(recipeId, canCraft);
|
||||
|
||||
recipes.Add(entry);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
using Content.Server.DoAfter;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Stack;
|
||||
using Content.Shared._CP14.Knowledge;
|
||||
using Content.Shared._CP14.Workbench;
|
||||
using Content.Shared._CP14.Workbench.Prototypes;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
@@ -30,7 +29,6 @@ public sealed partial class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
|
||||
[Dependency] private readonly UserInterfaceSystem _userInterface = default!;
|
||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedCP14KnowledgeSystem _knowledge = default!;
|
||||
|
||||
private EntityQuery<MetaDataComponent> _metaQuery;
|
||||
private EntityQuery<StackComponent> _stackQuery;
|
||||
@@ -138,7 +136,7 @@ public sealed partial class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
|
||||
{
|
||||
foreach (var req in recipe.Requirements)
|
||||
{
|
||||
if (!req.CheckRequirement(EntityManager, _proto, entities, user))
|
||||
if (!req.CheckRequirement(EntityManager, _proto, entities, user, recipe))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ namespace Content.Shared.Input
|
||||
public static readonly BoundKeyFunction MappingOpenContextMenu = "MappingOpenContextMenu";
|
||||
|
||||
//CP14 keys
|
||||
public static readonly BoundKeyFunction CP14OpenKnowledgeMenu = "CP14OpenKnowledgeMenu";
|
||||
public static readonly BoundKeyFunction CP14OpenSkillMenu = "CP14OpenSkillMenu";
|
||||
//CP14 keys end
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Preferences.Loadouts.Effects;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -50,4 +52,10 @@ public sealed partial class LoadoutPrototype : IPrototype, IEquipmentLoadout
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<EntProtoId> Actions { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// CP14 - it is possible to give skill trees to players who have taken this loadout
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public Dictionary<ProtoId<CP14SkillTreePrototype>, FixedPoint2> SkillTree = new();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Linq;
|
||||
using Content.Shared._CP14.Skill;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
@@ -25,6 +26,7 @@ public abstract class SharedStationSpawningSystem : EntitySystem
|
||||
[Dependency] private readonly SharedStorageSystem _storage = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _xformSystem = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _action = default!; //CP14
|
||||
[Dependency] private readonly CP14SharedSkillSystem _skill = default!; //CP14
|
||||
|
||||
private EntityQuery<HandsComponent> _handsQuery;
|
||||
private EntityQuery<InventoryComponent> _inventoryQuery;
|
||||
@@ -90,7 +92,7 @@ public abstract class SharedStationSpawningSystem : EntitySystem
|
||||
{
|
||||
EquipStartingGear(entity, loadout.StartingGear, raiseEvent);
|
||||
EquipStartingGear(entity, (IEquipmentLoadout) loadout, raiseEvent);
|
||||
CP14EquipStartingActions(entity, loadout);
|
||||
CP14EquipStartingActions(entity, loadout); //CP14
|
||||
}
|
||||
|
||||
private void CP14EquipStartingActions(EntityUid entity, LoadoutPrototype loadout)
|
||||
@@ -99,6 +101,11 @@ public abstract class SharedStationSpawningSystem : EntitySystem
|
||||
{
|
||||
_action.AddAction(entity, action);
|
||||
}
|
||||
|
||||
foreach (var tree in loadout.SkillTree)
|
||||
{
|
||||
_skill.TryAddExperience(entity, tree.Key, tree.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -96,10 +96,10 @@ namespace Content.Shared.Verbs
|
||||
|
||||
public static readonly VerbCategory CP14CurrencyConvert = new("cp14-verb-categories-currency-converter", null); //CP14
|
||||
|
||||
public static readonly VerbCategory CP14KnowledgeAdd = new("cp14-verb-categories-knowledge-add", null); //CP14
|
||||
public static readonly VerbCategory CP14AdminSkillAdd =
|
||||
new ("cp14-verb-categories-admin-skill-add", null, iconsOnly: true) { Columns = 6 }; //CP14
|
||||
|
||||
public static readonly VerbCategory CP14KnowledgeRemove = new("cp14-verb-categories-knowledge-remove", null); //CP14
|
||||
|
||||
public static readonly VerbCategory CP14KnowledgeLearn = new("cp14-verb-categories-knowledge-learn", null); //CP14
|
||||
public static readonly VerbCategory CP14AdminSkillRemove =
|
||||
new ("cp14-verb-categories-admin-skill-remove", null, iconsOnly: true) { Columns = 6 }; //CP14
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,62 +0,0 @@
|
||||
using System.Text;
|
||||
using Content.Shared._CP14.Knowledge.Components;
|
||||
using Content.Shared.Paper;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Knowledge;
|
||||
|
||||
public sealed class CP14KnowledgePaperTextSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly PaperSystem _paper = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<CP14KnowledgePaperTextComponent, MapInitEvent>(OnPaperMapInit);
|
||||
}
|
||||
|
||||
private void OnPaperMapInit(Entity<CP14KnowledgePaperTextComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
if (!TryComp<PaperComponent>(ent, out var paperComponent))
|
||||
return;
|
||||
|
||||
var paper = new Entity<PaperComponent>(ent, paperComponent);
|
||||
|
||||
if (!TryComp<CP14KnowledgeLearningSourceComponent>(ent, out var knowledge))
|
||||
return;
|
||||
|
||||
if (knowledge.Knowledge.Count == 0)
|
||||
return;
|
||||
|
||||
var content = GenerateText(knowledge);
|
||||
|
||||
_paper.SetContent(paper, content);
|
||||
paper.Comp.EditingDisabled = true;
|
||||
|
||||
// Yes we need to do synchronization after such changes,
|
||||
// yes predict, but we need to
|
||||
Dirty(paper);
|
||||
}
|
||||
|
||||
private string GenerateText(CP14KnowledgeLearningSourceComponent source)
|
||||
{
|
||||
var stringBuilder = new StringBuilder();
|
||||
|
||||
// Header
|
||||
stringBuilder.Append(Loc.GetString("cp14-knowledge-book-pre-text"));
|
||||
|
||||
// Main body
|
||||
foreach (var prototypeId in source.Knowledge)
|
||||
{
|
||||
if (!_prototype.TryIndex(prototypeId, out var indexedKnowledge))
|
||||
continue;
|
||||
|
||||
stringBuilder.Append($"\n{Loc.GetString(indexedKnowledge.Desc)}");
|
||||
}
|
||||
|
||||
// Footer
|
||||
stringBuilder.Append($"\n\n{Loc.GetString("cp14-knowledge-book-post-text")}");
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._CP14.Knowledge.Components;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class CP14AllKnowingComponent : Component;
|
||||
@@ -1,15 +0,0 @@
|
||||
using Content.Shared._CP14.Knowledge.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Knowledge.Components;
|
||||
|
||||
/// <summary>
|
||||
/// The ability to add a <see cref="CP14KnowledgePrototype"/> to an entity
|
||||
/// and quickly teach it some skills.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(SharedCP14KnowledgeSystem))]
|
||||
public sealed partial class CP14AutoAddKnowledgeComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public List<ProtoId<CP14KnowledgePrototype>> Knowledge = [];
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using Content.Shared._CP14.Knowledge.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Knowledge.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Allows new knowledge to be learnt through interactions with an object.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(SharedCP14KnowledgeSystem))]
|
||||
public sealed partial class CP14KnowledgeLearningSourceComponent : Component
|
||||
{
|
||||
[DataField, ViewVariables(VVAccess.ReadOnly)]
|
||||
public HashSet<ProtoId<CP14KnowledgePrototype>> Knowledge { get; private set; } = [];
|
||||
|
||||
[DataField]
|
||||
public TimeSpan DoAfter = TimeSpan.FromSeconds(5f);
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace Content.Shared._CP14.Knowledge.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Automatically generates content for PaperComponent,
|
||||
/// based on the knowledge that can be learnt from this object.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(SharedCP14KnowledgeSystem))]
|
||||
public sealed partial class CP14KnowledgePaperTextComponent : Component;
|
||||
@@ -1,14 +0,0 @@
|
||||
using Content.Shared._CP14.Knowledge.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Knowledge.Components;
|
||||
|
||||
/// <summary>
|
||||
/// A list of <see cref="CP14KnowledgePrototype"/> learned by this entity.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(SharedCP14KnowledgeSystem))]
|
||||
public sealed partial class CP14KnowledgeStorageComponent : Component
|
||||
{
|
||||
[DataField, ViewVariables(VVAccess.ReadOnly)]
|
||||
public HashSet<ProtoId<CP14KnowledgePrototype>> Knowledge { get; private set; } = [];
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using Content.Shared._CP14.Knowledge.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.Knowledge.Events;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class CP14KnowledgeInfoEvent : EntityEventArgs
|
||||
{
|
||||
public readonly NetEntity NetEntity;
|
||||
public readonly HashSet<ProtoId<CP14KnowledgePrototype>> AllKnowledge;
|
||||
|
||||
public CP14KnowledgeInfoEvent(NetEntity netEntity, HashSet<ProtoId<CP14KnowledgePrototype>> allKnowledge)
|
||||
{
|
||||
NetEntity = netEntity;
|
||||
AllKnowledge = allKnowledge;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
using Content.Shared._CP14.Knowledge.Prototypes;
|
||||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.Knowledge.Events;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CP14KnowledgeLearnDoAfterEvent : DoAfterEvent
|
||||
{
|
||||
public ProtoId<CP14KnowledgePrototype> Knowledge;
|
||||
|
||||
public override DoAfterEvent Clone()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using Content.Shared._CP14.Knowledge.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Knowledge.Events;
|
||||
|
||||
public sealed class CP14KnowledgeUsedEvent : EntityEventArgs
|
||||
{
|
||||
public readonly EntityUid User;
|
||||
public readonly ProtoId<CP14KnowledgePrototype> Knowledge;
|
||||
public readonly float Factor;
|
||||
|
||||
public CP14KnowledgeUsedEvent(EntityUid uid, ProtoId<CP14KnowledgePrototype> knowledge, float factor)
|
||||
{
|
||||
User = uid;
|
||||
Knowledge = knowledge;
|
||||
Factor = factor;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.Knowledge.Events;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class CP14RequestKnowledgeInfoEvent : EntityEventArgs
|
||||
{
|
||||
public readonly NetEntity NetEntity;
|
||||
|
||||
public CP14RequestKnowledgeInfoEvent(NetEntity netEntity)
|
||||
{
|
||||
NetEntity = netEntity;
|
||||
}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Knowledge.Prototypes;
|
||||
|
||||
/// <summary>
|
||||
/// Abstract knowledge that may be required to use items or crafts.
|
||||
/// </summary>
|
||||
[Prototype("CP14Knowledge")]
|
||||
public sealed partial class CP14KnowledgePrototype : IPrototype
|
||||
{
|
||||
[IdDataField]
|
||||
public string ID { get; private set; } = default!;
|
||||
|
||||
[DataField(required: true)]
|
||||
public LocId Name { get; private set; }
|
||||
|
||||
[DataField]
|
||||
public LocId Desc { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// To study this knowledge, other knowledge on which it is based may be necessary.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public HashSet<ProtoId<CP14KnowledgePrototype>> Dependencies = [];
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using Content.Shared._CP14.Knowledge.Components;
|
||||
using Content.Shared._CP14.Knowledge.Events;
|
||||
using Content.Shared._CP14.Knowledge.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Knowledge;
|
||||
|
||||
public abstract class SharedCP14KnowledgeSystem : EntitySystem
|
||||
{
|
||||
public bool HasKnowledge(Entity<CP14KnowledgeStorageComponent?> entity, ProtoId<CP14KnowledgePrototype> knowledge)
|
||||
{
|
||||
if (HasComp<CP14AllKnowingComponent>(entity))
|
||||
return true;
|
||||
|
||||
return Resolve(entity, ref entity.Comp, false) && entity.Comp.Knowledge.Contains(knowledge);
|
||||
}
|
||||
|
||||
public bool TryUseKnowledge(Entity<CP14KnowledgeStorageComponent?> entity, ProtoId<CP14KnowledgePrototype> knowledge, float factor = 1f)
|
||||
{
|
||||
if (!Resolve(entity, ref entity.Comp, false))
|
||||
return false;
|
||||
|
||||
if (!entity.Comp.Knowledge.Contains(knowledge))
|
||||
return false;
|
||||
|
||||
var ev = new CP14KnowledgeUsedEvent(entity, knowledge, factor);
|
||||
RaiseLocalEvent(entity, ev);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
@@ -1,39 +1,46 @@
|
||||
using Content.Shared._CP14.Knowledge;
|
||||
using Content.Shared._CP14.Knowledge.Prototypes;
|
||||
using Content.Shared._CP14.Skill;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared._CP14.Workbench.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Shared._CP14.Workbench.Requirements;
|
||||
|
||||
public sealed partial class KnowledgeRequired : CP14WorkbenchCraftRequirement
|
||||
public sealed partial class SkillRequired : CP14WorkbenchCraftRequirement
|
||||
{
|
||||
/// <summary>
|
||||
/// If the player does not have this knowledge, the recipe will not be displayed in the workbench.
|
||||
/// </summary>
|
||||
public override bool HideRecipe { get; set; } = true;
|
||||
|
||||
[DataField(required: true)]
|
||||
public ProtoId<CP14KnowledgePrototype> Knowledge;
|
||||
public List<ProtoId<CP14SkillPrototype>> Skills = new();
|
||||
|
||||
public override bool CheckRequirement(EntityManager entManager,
|
||||
IPrototypeManager protoManager,
|
||||
HashSet<EntityUid> placedEntities,
|
||||
EntityUid user)
|
||||
EntityUid user,
|
||||
CP14WorkbenchRecipePrototype recipe)
|
||||
{
|
||||
var knowledgeSystem = entManager.System<SharedCP14KnowledgeSystem>();
|
||||
var knowledgeSystem = entManager.System<CP14SharedSkillSystem>();
|
||||
|
||||
return knowledgeSystem.HasKnowledge(user, Knowledge);
|
||||
var haveAllSkills = true;
|
||||
foreach (var skill in Skills)
|
||||
{
|
||||
if (!knowledgeSystem.HaveSkill(user, skill))
|
||||
{
|
||||
haveAllSkills = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return haveAllSkills;
|
||||
}
|
||||
|
||||
public override void PostCraft(EntityManager entManager, HashSet<EntityUid> placedEntities, EntityUid user)
|
||||
{
|
||||
var knowledgeSystem = entManager.System<SharedCP14KnowledgeSystem>();
|
||||
knowledgeSystem.TryUseKnowledge(user, Knowledge);
|
||||
}
|
||||
|
||||
public override string GetRequirementTitle(IPrototypeManager protoManager)
|
||||
{
|
||||
return !protoManager.TryIndex(Knowledge, out var indexedKnowledge)
|
||||
? "Error knowledge"
|
||||
: $"{Loc.GetString("cp14-knowledge")}: {Loc.GetString(indexedKnowledge.Name)}";
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public override EntityPrototype? GetRequirementEntityView(IPrototypeManager protoManager)
|
||||
@@ -41,8 +48,8 @@ public sealed partial class KnowledgeRequired : CP14WorkbenchCraftRequirement
|
||||
return null;
|
||||
}
|
||||
|
||||
public override SpriteSpecifier GetRequirementTexture(IPrototypeManager protoManager)
|
||||
public override SpriteSpecifier? GetRequirementTexture(IPrototypeManager protoManager)
|
||||
{
|
||||
return new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/students-cap.svg.192dpi.png"));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
using Content.Shared._CP14.Material;
|
||||
using Content.Shared._CP14.Workbench.Prototypes;
|
||||
using Content.Shared.Materials;
|
||||
using Content.Shared.Stacks;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -13,13 +14,20 @@ namespace Content.Shared._CP14.Workbench.Requirements;
|
||||
|
||||
public sealed partial class MaterialResource : CP14WorkbenchCraftRequirement
|
||||
{
|
||||
public override bool HideRecipe { get; set; } = false;
|
||||
|
||||
[DataField(required: true)]
|
||||
public ProtoId<MaterialPrototype> Material;
|
||||
|
||||
[DataField]
|
||||
public int Count = 1;
|
||||
|
||||
public override bool CheckRequirement(EntityManager entManager, IPrototypeManager protoManager, HashSet<EntityUid> placedEntities, EntityUid user)
|
||||
public override bool CheckRequirement(
|
||||
EntityManager entManager,
|
||||
IPrototypeManager protoManager,
|
||||
HashSet<EntityUid> placedEntities,
|
||||
EntityUid user,
|
||||
CP14WorkbenchRecipePrototype recipe)
|
||||
{
|
||||
var count = 0;
|
||||
foreach (var ent in placedEntities)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* https://github.com/space-wizards/space-station-14/blob/master/LICENSE.TXT
|
||||
*/
|
||||
|
||||
using Content.Shared._CP14.Workbench.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -10,6 +11,8 @@ namespace Content.Shared._CP14.Workbench.Requirements;
|
||||
|
||||
public sealed partial class ProtoIdResource : CP14WorkbenchCraftRequirement
|
||||
{
|
||||
public override bool HideRecipe { get; set; } = false;
|
||||
|
||||
[DataField(required: true)]
|
||||
public EntProtoId ProtoId;
|
||||
|
||||
@@ -19,7 +22,8 @@ public sealed partial class ProtoIdResource : CP14WorkbenchCraftRequirement
|
||||
public override bool CheckRequirement(EntityManager entManager,
|
||||
IPrototypeManager protoManager,
|
||||
HashSet<EntityUid> placedEntities,
|
||||
EntityUid user)
|
||||
EntityUid user,
|
||||
CP14WorkbenchRecipePrototype recipe)
|
||||
{
|
||||
var indexedIngredients = IndexIngredients(entManager, placedEntities);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* https://github.com/space-wizards/space-station-14/blob/master/LICENSE.TXT
|
||||
*/
|
||||
|
||||
using Content.Shared._CP14.Workbench.Prototypes;
|
||||
using Content.Shared.Stacks;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -11,6 +12,8 @@ namespace Content.Shared._CP14.Workbench.Requirements;
|
||||
|
||||
public sealed partial class StackResource : CP14WorkbenchCraftRequirement
|
||||
{
|
||||
public override bool HideRecipe { get; set; } = false;
|
||||
|
||||
[DataField(required: true)]
|
||||
public ProtoId<StackPrototype> Stack;
|
||||
|
||||
@@ -20,7 +23,8 @@ public sealed partial class StackResource : CP14WorkbenchCraftRequirement
|
||||
public override bool CheckRequirement(EntityManager entManager,
|
||||
IPrototypeManager protoManager,
|
||||
HashSet<EntityUid> placedEntities,
|
||||
EntityUid user)
|
||||
EntityUid user,
|
||||
CP14WorkbenchRecipePrototype recipe)
|
||||
{
|
||||
var count = 0;
|
||||
foreach (var ent in placedEntities)
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* https://github.com/space-wizards/space-station-14/blob/master/LICENSE.TXT
|
||||
*/
|
||||
|
||||
using Content.Shared._CP14.Workbench.Prototypes;
|
||||
using Content.Shared.Tag;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -11,6 +12,8 @@ namespace Content.Shared._CP14.Workbench.Requirements;
|
||||
|
||||
public sealed partial class TagResource : CP14WorkbenchCraftRequirement
|
||||
{
|
||||
public override bool HideRecipe { get; set; } = false;
|
||||
|
||||
[DataField(required: true)]
|
||||
public ProtoId<TagPrototype> Tag;
|
||||
|
||||
@@ -23,7 +26,12 @@ public sealed partial class TagResource : CP14WorkbenchCraftRequirement
|
||||
[DataField(required: true)]
|
||||
public SpriteSpecifier? Texture;
|
||||
|
||||
public override bool CheckRequirement(EntityManager entManager, IPrototypeManager protoManager, HashSet<EntityUid> placedEntities, EntityUid user)
|
||||
public override bool CheckRequirement(
|
||||
EntityManager entManager,
|
||||
IPrototypeManager protoManager,
|
||||
HashSet<EntityUid> placedEntities,
|
||||
EntityUid user,
|
||||
CP14WorkbenchRecipePrototype recipe)
|
||||
{
|
||||
var tagSystem = entManager.System<TagSystem>();
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* https://github.com/space-wizards/space-station-14/blob/master/LICENSE.TXT
|
||||
*/
|
||||
|
||||
using Content.Shared._CP14.Workbench.Prototypes;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
@@ -13,6 +14,11 @@ namespace Content.Shared._CP14.Workbench;
|
||||
[MeansImplicitUse]
|
||||
public abstract partial class CP14WorkbenchCraftRequirement
|
||||
{
|
||||
/// <summary>
|
||||
/// If true, failure to fulfill this condition will hide recipes from the possible craft workbench menu
|
||||
/// </summary>
|
||||
public abstract bool HideRecipe { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Here a check is made that the recipe as a whole can be fulfilled at the current moment. Do not add anything that affects gameplay here, and only perform checks here.
|
||||
/// </summary>
|
||||
@@ -20,7 +26,8 @@ public abstract partial class CP14WorkbenchCraftRequirement
|
||||
public abstract bool CheckRequirement(EntityManager entManager,
|
||||
IPrototypeManager protoManager,
|
||||
HashSet<EntityUid> placedEntities,
|
||||
EntityUid user);
|
||||
EntityUid user,
|
||||
CP14WorkbenchRecipePrototype recipe);
|
||||
|
||||
/// <summary>
|
||||
/// An event that is triggered after crafting. This is the place to put important things like removing items, spending stacks or other things.
|
||||
|
||||
@@ -72,3 +72,8 @@
|
||||
license: "CC0-1.0"
|
||||
copyright: 'by magnuswaker on Freesound.org'
|
||||
source: "https://freesound.org/people/magnuswaker/sounds/563491/"
|
||||
|
||||
- files: ["skill_up1.ogg", "skill_up2.ogg", "skill_up3.ogg", "skill_up3.ogg"]
|
||||
license: "CC0-1.0"
|
||||
copyright: 'by IENBA on Freesound.org'
|
||||
source: "https://freesound.org/people/IENBA/sounds/752275/"
|
||||
|
||||
BIN
Resources/Audio/_CP14/Effects/skill_up1.ogg
Normal file
BIN
Resources/Audio/_CP14/Effects/skill_up1.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_CP14/Effects/skill_up2.ogg
Normal file
BIN
Resources/Audio/_CP14/Effects/skill_up2.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_CP14/Effects/skill_up3.ogg
Normal file
BIN
Resources/Audio/_CP14/Effects/skill_up3.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/_CP14/Effects/skill_up4.ogg
Normal file
BIN
Resources/Audio/_CP14/Effects/skill_up4.ogg
Normal file
Binary file not shown.
@@ -1,2 +0,0 @@
|
||||
cp14-knowledge-info-title = Character knowledge
|
||||
cp14-knowledge = Knowledge
|
||||
2
Resources/Locale/en-US/_CP14/knowledge/knowledge.ftl
Normal file
2
Resources/Locale/en-US/_CP14/knowledge/knowledge.ftl
Normal file
@@ -0,0 +1,2 @@
|
||||
cp14-learned-new-knowledge = You learned how to create [bold]"{$name}[/bold]"!
|
||||
cp14-forgot-knowledge = You forgot how to create [bold]"{$name}[/bold]"!
|
||||
@@ -1,18 +0,0 @@
|
||||
cp14-skill-label = [bold]Skill requirements[/bold]
|
||||
cp14-skill-examined = You need to have one of the following skills to use {$item}:
|
||||
cp14-skill-examined-need-all = You need to have all of the following skills in order to use {$item}:
|
||||
|
||||
cp14-skill-examined-skill = [color={$color}] - {$skill} [/color]
|
||||
|
||||
cp14-verb-categories-knowledge-add = Add knowledge:
|
||||
cp14-verb-categories-knowledge-remove = Delete knowledge:
|
||||
cp14-verb-categories-knowledge-learn = Learn knowledge:
|
||||
cp14-learned-new-knowledge = You have learned the knowledge of [bold]"{$name}[/bold]"!
|
||||
cp14-forgot-knowledge = You've lost your knowledge of [bold]"{$name}[/bold]"!
|
||||
|
||||
cp14-cant-learn-knowledge-dependencies =
|
||||
You were unable to understand {$target}...
|
||||
You lack the following knowledge:
|
||||
|
||||
cp14-knowledge-book-pre-text = Here you will find detailed instructions that explain
|
||||
cp14-knowledge-book-post-text = (To explore this knowledge, right-click on the book, and select ‘Learn Knowledge‘)
|
||||
@@ -1,6 +0,0 @@
|
||||
cp14-skill-issue-drops = The {$item} falls awkwardly out of your hands!
|
||||
cp14-skill-issue-recoil = You don't hold the recoil!
|
||||
cp14-skill-issue-self-harm = You're accidentally hitting on yourself!
|
||||
cp14-skill-issue-sharp-self-harm = You accidentally cut yourself!
|
||||
cp14-skill-issue-sharp-weapon-harm = You accidentally damaged the {$item}!
|
||||
cp14-skill-issue-push = You accidentally drop {$item}!
|
||||
@@ -1,24 +0,0 @@
|
||||
# T1
|
||||
|
||||
cp14-knowledge-sewing-name = Clothing sewing
|
||||
cp14-knowledge-sewing-desc = how to make simple clothes on sewing table
|
||||
|
||||
cp14-knowledge-wallpaper-name = Wallpaper production
|
||||
cp14-knowledge-wallpaper-desc = how to create wallpaper on sewing table
|
||||
|
||||
cp14-knowledge-woodwork-name = Woodwork
|
||||
cp14-knowledge-woodwork-desc = how to make simple objects out of wood
|
||||
|
||||
cp14-knowledge-metall-melting-name = Metall melting
|
||||
cp14-knowledge-metall-melting-desc = how to smelt ore into valuable metals
|
||||
|
||||
cp14-knowledge-metall-forging-name = Metall forging
|
||||
cp14-knowledge-metall-forging-desc = how to forge metal into different shapes
|
||||
|
||||
cp14-knowledge-glasswork-name = Glasswork
|
||||
cp14-knowledge-glasswork-desc = how to work with glass.
|
||||
|
||||
# T2
|
||||
|
||||
cp14-knowledge-sewing2-name = Advanced clothing sewing
|
||||
cp14-knowledge-sewing2-desc = how to create quality clothes on sewing table
|
||||
@@ -12,6 +12,7 @@ cp14-loadout-general-shoes = Shoes
|
||||
cp14-loadout-general-back = Back
|
||||
cp14-loadout-general-trinkets = Trinkets
|
||||
cp14-loadout-general-spells = Spells
|
||||
cp14-loadout-skill-tree = Specialization
|
||||
cp14-loadout-general-keys = Keys
|
||||
|
||||
# Apprentice
|
||||
|
||||
22
Resources/Locale/en-US/_CP14/skill/skill_tree.ftl
Normal file
22
Resources/Locale/en-US/_CP14/skill/skill_tree.ftl
Normal file
@@ -0,0 +1,22 @@
|
||||
cp14-skill-tree-blaksmithing-name = Blacksmithing
|
||||
cp14-skill-tree-blaksmithing-desc = Explore and create new items from metal.
|
||||
|
||||
cp14-skill-tree-pyrokinetic-name = Pyrokinetic
|
||||
cp14-skill-tree-pyrokinetic-desc = Master the magic of fire, allowing you to warm, illuminate, and destroy.
|
||||
|
||||
cp14-skill-tree-hydrosophistry-name = Hydrosophistry
|
||||
cp14-skill-tree-hydrosophistry-desc = Master the magic of water and frost to create items from water and ice, and freeze enemies.
|
||||
|
||||
cp14-skill-tree-metamagic-name = Metamagic
|
||||
cp14-skill-tree-metamagic-desc = Explore ways to subtly manipulate magic to affect spells and items.
|
||||
|
||||
cp14-skill-tree-illusion-name = Illusoriness
|
||||
cp14-skill-tree-illusion-desc = Explore the nature of light to create illusions, light sources and shadows.
|
||||
|
||||
cp14-skill-tree-healing-name = Lifecation
|
||||
cp14-skill-tree-healing-desc = Explore the ways in which magic affects living creatures.
|
||||
|
||||
# Body
|
||||
|
||||
cp14-skill-tree-atlethic-name = Atlethic
|
||||
cp14-skill-tree-atlethic-desc = Develop your body by pushing the boundaries of what is available.
|
||||
10
Resources/Locale/en-US/_CP14/skill/ui.ftl
Normal file
10
Resources/Locale/en-US/_CP14/skill/ui.ftl
Normal file
@@ -0,0 +1,10 @@
|
||||
cp14-verb-categories-admin-skill-add = Add skill
|
||||
cp14-verb-categories-admin-skill-remove = Remove skill
|
||||
|
||||
cp14-skill-info-title = Skills
|
||||
cp14-game-hud-open-skill-menu-button-tooltip = Skill tree
|
||||
|
||||
cp14-skill-menu-learn-button = Learn skill
|
||||
cp14-skill-menu-learncost = [color=yellow]Points required:[/color]
|
||||
cp14-skill-menu-skillpoints = Experience points:
|
||||
cp14-skill-menu-level = Level:
|
||||
@@ -1,2 +0,0 @@
|
||||
cp14-knowledge-info-title = Знания персонажа
|
||||
cp14-knowledge = Знания
|
||||
2
Resources/Locale/ru-RU/_CP14/knowledge/knowledge.ftl
Normal file
2
Resources/Locale/ru-RU/_CP14/knowledge/knowledge.ftl
Normal file
@@ -0,0 +1,2 @@
|
||||
cp14-learned-new-knowledge = Вы научились создавать [bold]"{$name}[/bold]"!
|
||||
cp14-forgot-knowledge = Вы забыли как создавать [bold]"{$name}[/bold]"!
|
||||
@@ -1,18 +0,0 @@
|
||||
cp14-skill-label = [bold]Требования к навыкам[/bold]
|
||||
cp14-skill-examined = Вам нужно владеть одним из следующих навыков, чтобы использовать {$item}:
|
||||
cp14-skill-examined-need-all = Вам нужно владеть всеми следующими навыками, чтобы использовать {$item}:
|
||||
|
||||
cp14-skill-examined-skill = [color={$color}] - {$skill} [/color]
|
||||
|
||||
cp14-verb-categories-knowledge-add = Научить знаниям:
|
||||
cp14-verb-categories-knowledge-remove = Удалить знания:
|
||||
cp14-verb-categories-knowledge-learn = Изучить знания:
|
||||
cp14-learned-new-knowledge = Вы изучили знания о [bold]"{$name}[/bold]"!
|
||||
cp14-forgot-knowledge = Вы потеряли свои знания о [bold]"{$name}[/bold]"!
|
||||
|
||||
cp14-cant-learn-knowledge-dependencies =
|
||||
Вы не смогли понять {$target}...
|
||||
Вам не хватает понимания:
|
||||
|
||||
cp14-knowledge-book-pre-text = Здесь подробно описаны инструкции, объясняющие
|
||||
cp14-knowledge-book-post-text = (Чтобы изучить эти знания, нажмите ПКМ по книге, и выберите "Изучить знания")
|
||||
@@ -1,6 +0,0 @@
|
||||
cp14-skill-issue-drops = {$item} неловко вываливается из ваших рук!
|
||||
cp14-skill-issue-recoil = Вы не удерживаете отдачу!
|
||||
cp14-skill-issue-self-harm = Вы случайно попадаете по себе!
|
||||
cp14-skill-issue-sharp-self-harm = Вы случайно порезались!
|
||||
cp14-skill-issue-sharp-weapon-harm = Вы случайно повредили {$item}!
|
||||
cp14-skill-issue-push = Вы случайно роняете {$item}!
|
||||
@@ -1,24 +0,0 @@
|
||||
# T1
|
||||
|
||||
cp14-knowledge-sewing-name = Шитье одежды
|
||||
cp14-knowledge-sewing-desc = как создавать простую одежду на ткацком станке
|
||||
|
||||
cp14-knowledge-wallpaper-name = Изготовление обоев
|
||||
cp14-knowledge-wallpaper-desc = как создавать обои на ткацком станке
|
||||
|
||||
cp14-knowledge-woodwork-name = Работа по дереву
|
||||
cp14-knowledge-woodwork-desc = как создавать простые предметы из дерева
|
||||
|
||||
cp14-knowledge-metall-melting-name = Переплавка металлов
|
||||
cp14-knowledge-metall-melting-desc = как переплавлять руду в ценные металлы
|
||||
|
||||
cp14-knowledge-metall-forging-name = Ковка металлов
|
||||
cp14-knowledge-metall-forging-desc = как перековывать металл в различные формы
|
||||
|
||||
cp14-knowledge-glasswork-name = Работа с стеклом
|
||||
cp14-knowledge-glasswork-desc = как работать со стеклом
|
||||
|
||||
# T2
|
||||
|
||||
cp14-knowledge-sewing2-name = Продвинутое шитье одежды
|
||||
cp14-knowledge-sewing2-desc = как создавать качественную одежду на ткацком станке
|
||||
@@ -12,6 +12,7 @@ cp14-loadout-general-shoes = Обувь
|
||||
cp14-loadout-general-back = Спина
|
||||
cp14-loadout-general-trinkets = Безделушки
|
||||
cp14-loadout-general-spells = Заклинания
|
||||
cp14-loadout-skill-tree = Специализация
|
||||
cp14-loadout-general-keys = Ключи
|
||||
|
||||
# Apprentice
|
||||
|
||||
24
Resources/Locale/ru-RU/_CP14/skill/skill_tree.ftl
Normal file
24
Resources/Locale/ru-RU/_CP14/skill/skill_tree.ftl
Normal file
@@ -0,0 +1,24 @@
|
||||
cp14-skill-tree-blaksmithing-name = Кузнечное дело
|
||||
cp14-skill-tree-blaksmithing-desc = Исследуйте и создавайте новые предметы из металла.
|
||||
|
||||
# Magic
|
||||
|
||||
cp14-skill-tree-pyrokinetic-name = Пирокинетика
|
||||
cp14-skill-tree-pyrokinetic-desc = Овладейте магией огня, позволяющей вам согревать, освещать и уничтожать.
|
||||
|
||||
cp14-skill-tree-hydrosophistry-name = Гидрософистика
|
||||
cp14-skill-tree-hydrosophistry-desc = Овладейте магией воды и мороза, чтобы создавать предметы из воды и льда, и замораживать врагов.
|
||||
|
||||
cp14-skill-tree-metamagic-name = Метамагия
|
||||
cp14-skill-tree-metamagic-desc = Исследуйте способы тонкой манипуляции магии, чтобы влиять на заклинания и предметы.
|
||||
|
||||
cp14-skill-tree-illusion-name = Иллюзорность
|
||||
cp14-skill-tree-illusion-desc = Исследуйте природу света, чтобы создавать иллюзии, источники света и тени.
|
||||
|
||||
cp14-skill-tree-healing-name = Жизнетворение
|
||||
cp14-skill-tree-healing-desc = Изучайте способы влияния магии на живые создания.
|
||||
|
||||
# Body
|
||||
|
||||
cp14-skill-tree-atlethic-name = Атлетика
|
||||
cp14-skill-tree-atlethic-desc = Развивайте свое тело, расширяя границы доступного.
|
||||
10
Resources/Locale/ru-RU/_CP14/skill/ui.ftl
Normal file
10
Resources/Locale/ru-RU/_CP14/skill/ui.ftl
Normal file
@@ -0,0 +1,10 @@
|
||||
cp14-verb-categories-admin-skill-add = Выдать навык
|
||||
cp14-verb-categories-admin-skill-remove = Удалить навык
|
||||
|
||||
cp14-skill-info-title = Навыки
|
||||
cp14-game-hud-open-skill-menu-button-tooltip = Деревья навыков
|
||||
|
||||
cp14-skill-menu-learn-button = Изучить навык
|
||||
cp14-skill-menu-learncost = [color=yellow]Требуется очков:[/color]
|
||||
cp14-skill-menu-skillpoints = Очков опыта:
|
||||
cp14-skill-menu-level = Уровень:
|
||||
@@ -38457,14 +38457,6 @@ entities:
|
||||
- type: Transform
|
||||
pos: 6.771952,-30.18434
|
||||
parent: 2
|
||||
- proto: CP14BookKnowledgeWallpaperCraft
|
||||
entities:
|
||||
- uid: 7131
|
||||
components:
|
||||
- type: Transform
|
||||
parent: 7130
|
||||
- type: Physics
|
||||
canCollide: False
|
||||
- proto: CP14BookshelfWoodenFilled
|
||||
entities:
|
||||
- uid: 7133
|
||||
@@ -81110,9 +81102,6 @@ entities:
|
||||
parent: 2
|
||||
- type: Storage
|
||||
storedItems:
|
||||
7131:
|
||||
position: 0,0
|
||||
_rotation: South
|
||||
7132:
|
||||
position: 1,0
|
||||
_rotation: South
|
||||
@@ -81122,7 +81111,6 @@ entities:
|
||||
showEnts: False
|
||||
occludes: True
|
||||
ents:
|
||||
- 7131
|
||||
- 7132
|
||||
- uid: 14258
|
||||
components:
|
||||
|
||||
@@ -329,27 +329,6 @@ entities:
|
||||
- type: Transform
|
||||
pos: -2.5,-9.5
|
||||
parent: 2
|
||||
- proto: CP14BookKnowledgeGlasswork
|
||||
entities:
|
||||
- uid: 67
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 1.7399222,-0.32284212
|
||||
parent: 2
|
||||
- proto: CP14BookKnowledgeMetallForging
|
||||
entities:
|
||||
- uid: 68
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 2.2238452,-0.34533072
|
||||
parent: 2
|
||||
- proto: CP14BookKnowledgeMetallMelting
|
||||
entities:
|
||||
- uid: 322
|
||||
components:
|
||||
- type: Transform
|
||||
pos: 2.696513,-0.36781955
|
||||
parent: 2
|
||||
- proto: CP14WoodenChest
|
||||
entities:
|
||||
- uid: 205
|
||||
|
||||
@@ -66852,13 +66852,6 @@ entities:
|
||||
rot: 6.283185307179586 rad
|
||||
pos: 36.98452,-65.53377
|
||||
parent: 2
|
||||
- proto: CP14BookKnowledgeClothingSewing
|
||||
entities:
|
||||
- uid: 14134
|
||||
components:
|
||||
- type: Transform
|
||||
pos: -29.079868,-22.234352
|
||||
parent: 2
|
||||
- proto: CP14BowCombat
|
||||
entities:
|
||||
- uid: 17516
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
name: admin observer
|
||||
categories: [ HideSpawnMenu ]
|
||||
components:
|
||||
- type: CP14AllKnowing
|
||||
- type: ContentEye
|
||||
maxZoom: 8.916104, 8.916104
|
||||
- type: Tag
|
||||
|
||||
@@ -164,35 +164,6 @@
|
||||
amount: 5
|
||||
- id: CP14PenFeather
|
||||
amount: 3
|
||||
|
||||
|
||||
- type: storePositionBuy
|
||||
id: CP14BookKnowledgeMetallMelting
|
||||
code: KNOWLEDGE_MELTING
|
||||
price: 100
|
||||
factions:
|
||||
- SpiceStream
|
||||
service: !type:CP14BuyItemsService
|
||||
product: CP14BookKnowledgeMetallMelting
|
||||
|
||||
- type: storePositionBuy
|
||||
id: CP14BookKnowledgeMetallForging
|
||||
code: KNOWLEDGE_FORGING
|
||||
price: 100
|
||||
factions:
|
||||
- SpiceStream
|
||||
service: !type:CP14BuyItemsService
|
||||
product: CP14BookKnowledgeMetallForging
|
||||
|
||||
- type: storePositionBuy
|
||||
id: CP14BookKnowledgeGlasswork
|
||||
code: KNOWLEDGE_GLASSWORK
|
||||
price: 100
|
||||
factions:
|
||||
- SpiceStream
|
||||
service: !type:CP14BuyItemsService
|
||||
product: CP14BookKnowledgeGlasswork
|
||||
|
||||
|
||||
- type: storePositionBuy
|
||||
id: EnergyCrystals
|
||||
|
||||
@@ -0,0 +1,109 @@
|
||||
- type: entity
|
||||
id: CP14ActionSpellIceArrow
|
||||
name: Ice arrow
|
||||
description: You create a temporary sharp ice arrow that can be used as a disposable bow projectile.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _CP14/Actions/Spells/water.rsi
|
||||
state: ice_arrow
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 20
|
||||
- type: CP14MagicEffect
|
||||
effects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
- CP14ImpactEffectWaterCreation
|
||||
- !type:CP14SpellSpawnInHandEntity
|
||||
spawns:
|
||||
- CP14IceArrow
|
||||
- type: CP14MagicEffectVerbalAspect
|
||||
startSpeech: "Sagitta glaciei..."
|
||||
endSpeech: "in manu mea"
|
||||
- type: CP14MagicEffectSomaticAspect
|
||||
- type: CP14MagicEffectCastingVisual
|
||||
proto: CP14RuneWaterCreation
|
||||
- type: InstantAction
|
||||
itemIconStyle: BigAction
|
||||
sound: !type:SoundPathSpecifier
|
||||
path: /Audio/Magic/rumble.ogg
|
||||
icon:
|
||||
sprite: _CP14/Actions/Spells/water.rsi
|
||||
state: ice_arrow
|
||||
event: !type:CP14DelayedInstantActionEvent
|
||||
cooldown: 5
|
||||
breakOnMove: false
|
||||
|
||||
- type: entity
|
||||
id: CP14IceArrow
|
||||
parent: BaseItem
|
||||
name: ice arrow
|
||||
description: A sharp ice arrow created with magic. It melts and will soon disappear, but you can shoot it once with your bow.
|
||||
categories: [ ForkFiltered ]
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _CP14/Objects/Weapons/Ranged/Projectiles/ice_arrow.rsi
|
||||
state: icon
|
||||
- type: Item
|
||||
storedRotation: 0
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape: !type:PhysShapeCircle
|
||||
radius: 0.2
|
||||
density: 5
|
||||
mask:
|
||||
- ItemMask
|
||||
restitution: 0.3
|
||||
friction: 0.2
|
||||
projectile:
|
||||
shape:
|
||||
!type:PhysShapeAabb
|
||||
bounds: "-0.1,-0.1,0.1,0.1"
|
||||
hard: false
|
||||
mask:
|
||||
- Impassable
|
||||
- BulletImpassable
|
||||
- type: EmbeddableProjectile
|
||||
sound: /Audio/Weapons/star_hit.ogg
|
||||
embedOnThrow: false
|
||||
- type: ThrowingAngle
|
||||
angle: 0
|
||||
- type: Ammo
|
||||
muzzleFlash: null
|
||||
- type: Tag
|
||||
tags:
|
||||
- CP14Arrow
|
||||
- type: Projectile
|
||||
deleteOnCollide: false
|
||||
onlyCollideWhenShot: true
|
||||
damage:
|
||||
types:
|
||||
Piercing: 17
|
||||
Cold: 5
|
||||
- type: Damageable
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 10
|
||||
behaviors:
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
collection: GlassBreak
|
||||
- !type:DoActsBehavior
|
||||
acts: ["Destruction"]
|
||||
- type: TimedDespawn
|
||||
lifetime: 60
|
||||
- type: DamageOnLand
|
||||
damage:
|
||||
types:
|
||||
Blunt: 10
|
||||
|
||||
- type: entity
|
||||
parent: CP14BaseSpellScrollWater
|
||||
id: CP14SpellScrollIceArrow
|
||||
name: ice arrow spell scroll
|
||||
components:
|
||||
- type: CP14SpellStorage
|
||||
spells:
|
||||
- CP14ActionSpellIceArrow
|
||||
@@ -0,0 +1,146 @@
|
||||
- type: entity
|
||||
id: CP14ActionSpellIceDagger
|
||||
name: Ice dagger
|
||||
description: You form an icy sharp dagger that will do for temporary use.
|
||||
components:
|
||||
- type: Sprite
|
||||
sprite: _CP14/Actions/Spells/water.rsi
|
||||
state: ice_dagger
|
||||
- type: CP14MagicEffectManaCost
|
||||
manaCost: 15
|
||||
- type: CP14MagicEffect
|
||||
effects:
|
||||
- !type:CP14SpellSpawnEntityOnTarget
|
||||
spawns:
|
||||
- CP14ImpactEffectWaterCreation
|
||||
- !type:CP14SpellSpawnInHandEntity
|
||||
spawns:
|
||||
- CP14IceDagger
|
||||
- type: CP14MagicEffectVerbalAspect
|
||||
startSpeech: "Un pittore sulla..."
|
||||
endSpeech: "soglia della mano"
|
||||
- type: CP14MagicEffectSomaticAspect
|
||||
- type: CP14MagicEffectCastingVisual
|
||||
proto: CP14RuneWaterCreation
|
||||
- type: InstantAction
|
||||
itemIconStyle: BigAction
|
||||
sound: !type:SoundPathSpecifier
|
||||
path: /Audio/Magic/rumble.ogg
|
||||
icon:
|
||||
sprite: _CP14/Actions/Spells/water.rsi
|
||||
state: ice_dagger
|
||||
event: !type:CP14DelayedInstantActionEvent
|
||||
cooldown: 20
|
||||
breakOnMove: false
|
||||
|
||||
- type: entity
|
||||
name: ice dagger
|
||||
parent: BaseItem
|
||||
id: CP14IceDagger
|
||||
description: A sharp ice arrow created with magic. It melts and will soon disappear, but you can shoot it once with your bow.
|
||||
categories: [ ForkFiltered ]
|
||||
components:
|
||||
- type: Sharp
|
||||
- type: Sprite
|
||||
sprite: _CP14/Objects/Weapons/Melee/ice_dagger.rsi
|
||||
state: icon
|
||||
- type: MeleeWeapon
|
||||
resetOnHandSelected: false #Fast swap
|
||||
range: 1.0 # 1.5 standart
|
||||
cPAnimationOffset: -0.75 #-1 standart
|
||||
attackRate: 1.5 # 1 standart
|
||||
angle: 45
|
||||
wideAnimationRotation: 135
|
||||
wideAnimation: CP14WeaponArcSlash
|
||||
damage:
|
||||
types:
|
||||
Slash: 2
|
||||
Piercing: 5
|
||||
Cold: 3
|
||||
soundHit:
|
||||
collection: MetalThud
|
||||
cPAnimationLength: 0.25
|
||||
- type: Clothing
|
||||
equipDelay: 0.25
|
||||
unequipDelay: 0.25
|
||||
quickEquip: false
|
||||
breakOnMove: false
|
||||
slots:
|
||||
- belt
|
||||
- type: CP14MeleeParriable
|
||||
- type: Item
|
||||
shape:
|
||||
- 0,0,0,1
|
||||
storedOffset: 0, 5
|
||||
storedRotation: 45
|
||||
size: Normal
|
||||
- type: ExaminableDamage
|
||||
messages: CP14WeaponMessages
|
||||
- type: DisarmMalus
|
||||
- type: ThrowingAngle
|
||||
angle: 135
|
||||
- type: EmbeddableProjectile
|
||||
offset: -0.15,-0.15
|
||||
removalTime: 0.5
|
||||
- type: LandAtCursor
|
||||
- type: DamageOtherOnHit
|
||||
damage:
|
||||
types:
|
||||
Piercing: 10
|
||||
Cold: 5
|
||||
- type: DamageOnLand
|
||||
damage:
|
||||
types:
|
||||
Blunt: 5
|
||||
- type: Fixtures
|
||||
fixtures:
|
||||
fix1:
|
||||
shape: !type:PolygonShape
|
||||
vertices:
|
||||
- -0.40,-0.30
|
||||
- -0.30,-0.40
|
||||
- 0.40,0.30
|
||||
- 0.30,0.40
|
||||
density: 10
|
||||
mask:
|
||||
- ItemMask
|
||||
restitution: 0.3
|
||||
friction: 0.2
|
||||
- type: CP14SharpeningStone
|
||||
- type: UseDelay
|
||||
- type: Tool
|
||||
qualities:
|
||||
- Slicing
|
||||
useSound:
|
||||
path: /Audio/Items/Culinary/chop.ogg
|
||||
- type: Utensil
|
||||
types:
|
||||
- Knife
|
||||
- type: CP14WallpaperRemover
|
||||
- type: CP14MeleeSelfDamage
|
||||
damageToSelf:
|
||||
types:
|
||||
Blunt: 1 # 10 hits
|
||||
- type: Damageable
|
||||
- type: Destructible
|
||||
thresholds:
|
||||
- trigger:
|
||||
!type:DamageTrigger
|
||||
damage: 10
|
||||
behaviors:
|
||||
- !type:PlaySoundBehavior
|
||||
sound:
|
||||
collection: GlassBreak
|
||||
- !type:DoActsBehavior
|
||||
acts: ["Destruction"]
|
||||
- type: TimedDespawn
|
||||
lifetime: 60
|
||||
|
||||
- type: entity
|
||||
parent: CP14BaseSpellScrollWater
|
||||
id: CP14SpellScrollIceDagger
|
||||
name: ice dagger spell scroll
|
||||
components:
|
||||
- type: CP14SpellStorage
|
||||
spells:
|
||||
- CP14ActionSpellIceDagger
|
||||
@@ -19,8 +19,9 @@
|
||||
- type: Loadout
|
||||
prototypes:
|
||||
- CP14MobSkeletonHalberd
|
||||
- type: CP14AutoLearnAction
|
||||
actions:
|
||||
- type: CP14SpellStorage
|
||||
grantAccessToSelf: true
|
||||
spells:
|
||||
- CP14ActionSpellKick
|
||||
|
||||
- type: entity
|
||||
@@ -42,8 +43,9 @@
|
||||
- type: Loadout
|
||||
prototypes:
|
||||
- CP14MobSkeletonDodger
|
||||
- type: CP14AutoLearnAction
|
||||
actions:
|
||||
- type: CP14SpellStorage
|
||||
grantAccessToSelf: true
|
||||
spells:
|
||||
- CP14ActionSpellSprint
|
||||
|
||||
- type: entity
|
||||
@@ -68,8 +70,9 @@
|
||||
- type: CP14MagicEnergyDraw
|
||||
energy: 1
|
||||
delay: 1
|
||||
- type: CP14AutoLearnAction
|
||||
actions:
|
||||
- type: CP14SpellStorage
|
||||
grantAccessToSelf: true
|
||||
spells:
|
||||
- CP14ActionSpellIceShards
|
||||
- CP14ActionSpellFreeze
|
||||
- CP14ActionSpellFlameCreation
|
||||
@@ -84,8 +87,9 @@
|
||||
- type: Loadout
|
||||
prototypes:
|
||||
- CP14MobSkeletonBard
|
||||
- type: CP14AutoLearnAction
|
||||
actions:
|
||||
- type: CP14SpellStorage
|
||||
grantAccessToSelf: true
|
||||
spells:
|
||||
- CP14ActionSpellHealBallade
|
||||
- CP14ActionSpellMagicBallade
|
||||
- CP14ActionSpellSpeedBallade
|
||||
|
||||
@@ -231,6 +231,7 @@
|
||||
types:
|
||||
Cold: 0.25
|
||||
Bloodloss: 0.25
|
||||
- type: CP14SkillStorage
|
||||
|
||||
|
||||
- type: entity
|
||||
@@ -309,7 +310,6 @@
|
||||
Asphyxiation: -1.0
|
||||
- type: FireVisuals
|
||||
alternateState: Standing #TODO - custom visuals
|
||||
- type: CP14KnowledgeStorage
|
||||
|
||||
- type: entity
|
||||
save: false
|
||||
|
||||
@@ -31,10 +31,6 @@
|
||||
- type: CP14MagicEnergyDraw #Half of standard mana regeneration
|
||||
energy: 0.5
|
||||
delay: 3
|
||||
- type: CP14SpellStorage
|
||||
grantAccessToSelf: true
|
||||
spells:
|
||||
- CP14ActionSpellManaConsumeElf
|
||||
- type: Inventory
|
||||
templateId: CP14Human
|
||||
displacements:
|
||||
|
||||
@@ -115,10 +115,6 @@
|
||||
- type: CP14MagicEnergyDraw #Cool x3 mana regen!
|
||||
energy: 1.5
|
||||
delay: 3
|
||||
- type: CP14SpellStorage
|
||||
grantAccessToSelf: true
|
||||
spells:
|
||||
- CP14ActionSpellSprintGoblin
|
||||
- type: Hands
|
||||
handDisplacement:
|
||||
sizeMaps:
|
||||
|
||||
@@ -74,10 +74,6 @@
|
||||
- id: CP14FoodMeatHuman # Replace it with silva meat, heh.
|
||||
amount: 5
|
||||
#- type: CP14MagicEnergyPhotosynthesis # Silva special feature #Disabled until sunlight fixed
|
||||
- type: CP14SpellStorage
|
||||
grantAccessToSelf: true
|
||||
spells:
|
||||
- CP14ActionSpellPlantGrowthSilva
|
||||
#- type: CP14MagicEnergyDraw #Enabled default mana regen until sunlight fixed
|
||||
# enable: false
|
||||
- type: Body
|
||||
|
||||
@@ -114,7 +114,6 @@
|
||||
- type: Inventory
|
||||
templateId: CP14Human
|
||||
- type: TransferMindOnGib
|
||||
- type: CP14KnowledgeStorage
|
||||
- type: CP14DemiplaneStabilizer
|
||||
enabled: false
|
||||
|
||||
|
||||
@@ -62,14 +62,4 @@
|
||||
- type: GuideHelp
|
||||
openOnActivation: true
|
||||
guides:
|
||||
- SS14
|
||||
|
||||
- type: entity
|
||||
parent: CP14BookBase
|
||||
id: CP14BookKnowledgeBase
|
||||
abstract: true
|
||||
categories: [ ForkFiltered ]
|
||||
name: knowledge book
|
||||
description: This book holds valuable knowledge that you can learn... if you're ready for it.
|
||||
components:
|
||||
- type: CP14KnowledgePaperText
|
||||
- SS14
|
||||
@@ -1,68 +0,0 @@
|
||||
# T0
|
||||
|
||||
- type: entity
|
||||
parent: CP14BookKnowledgeBase
|
||||
id: CP14BookKnowledgeWoodWork
|
||||
suffix: Wood Work
|
||||
components:
|
||||
- type: CP14KnowledgeLearningSource
|
||||
knowledge:
|
||||
- WoodWork
|
||||
|
||||
- type: entity
|
||||
parent: CP14BookKnowledgeBase
|
||||
id: CP14BookKnowledgeMetallMelting
|
||||
suffix: Metall Melting
|
||||
components:
|
||||
- type: CP14KnowledgeLearningSource
|
||||
knowledge:
|
||||
- MetallMelting
|
||||
|
||||
- type: entity
|
||||
parent: CP14BookKnowledgeBase
|
||||
id: CP14BookKnowledgeMetallForging
|
||||
suffix: Metall Forging
|
||||
components:
|
||||
- type: CP14KnowledgeLearningSource
|
||||
knowledge:
|
||||
- MetallForging
|
||||
|
||||
- type: entity
|
||||
parent: CP14BookKnowledgeBase
|
||||
id: CP14BookKnowledgeGlasswork
|
||||
suffix: Glasswork
|
||||
components:
|
||||
- type: CP14KnowledgeLearningSource
|
||||
knowledge:
|
||||
- Glasswork
|
||||
|
||||
# T1
|
||||
|
||||
- type: entity
|
||||
parent: CP14BookKnowledgeBase
|
||||
id: CP14BookKnowledgeClothingSewing
|
||||
suffix: Clothing Sewing
|
||||
components:
|
||||
- type: CP14KnowledgeLearningSource
|
||||
knowledge:
|
||||
- ClothingSewing
|
||||
|
||||
- type: entity
|
||||
parent: CP14BookKnowledgeBase
|
||||
id: CP14BookKnowledgeWallpaperCraft
|
||||
suffix: Wallpaper Craft
|
||||
components:
|
||||
- type: CP14KnowledgeLearningSource
|
||||
knowledge:
|
||||
- WallpaperCraft
|
||||
|
||||
# T2
|
||||
|
||||
- type: entity
|
||||
parent: CP14BookKnowledgeBase
|
||||
id: CP14BookKnowledgeAdvancedClothingSewing
|
||||
suffix: Advanced Clothing Sewing
|
||||
components:
|
||||
- type: CP14KnowledgeLearningSource
|
||||
knowledge:
|
||||
- AdvancedClothingSewing
|
||||
@@ -96,17 +96,6 @@
|
||||
- id: CP14BookRandom
|
||||
amount: !type:RangeNumberSelector
|
||||
range: 0, 15
|
||||
#Random knowledge
|
||||
- !type:GroupSelector
|
||||
prob: 0.15
|
||||
children:
|
||||
- id: CP14BookKnowledgeWoodWork
|
||||
- id: CP14BookKnowledgeMetallMelting
|
||||
- id: CP14BookKnowledgeMetallForging
|
||||
- id: CP14BookKnowledgeGlasswork
|
||||
- id: CP14BookKnowledgeClothingSewing
|
||||
- id: CP14BookKnowledgeWallpaperCraft
|
||||
- id: CP14BookKnowledgeAdvancedClothingSewing
|
||||
|
||||
- type: entity
|
||||
id: CP14BookshelfWoodenFilled
|
||||
|
||||
@@ -20,8 +20,9 @@
|
||||
- CP14MindRoleVampire
|
||||
components:
|
||||
- type: CP14Vampire
|
||||
- type: CP14AutoLearnAction
|
||||
actions:
|
||||
- type: CP14SpellStorage
|
||||
grantAccessToSelf: true
|
||||
spells:
|
||||
- CP14ActionVampireBite
|
||||
- CP14ActionSpellVampireHypnosis
|
||||
- CP14ActionSpellVampireBloodStep
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
# T0
|
||||
|
||||
- type: CP14Knowledge
|
||||
id: WoodWork
|
||||
name: cp14-knowledge-woodwork-name
|
||||
desc: cp14-knowledge-woodwork-desc
|
||||
|
||||
- type: CP14Knowledge
|
||||
id: MetallMelting
|
||||
name: cp14-knowledge-metall-melting-name
|
||||
desc: cp14-knowledge-metall-melting-desc
|
||||
|
||||
- type: CP14Knowledge
|
||||
id: MetallForging
|
||||
name: cp14-knowledge-metall-forging-name
|
||||
desc: cp14-knowledge-metall-forging-desc
|
||||
|
||||
- type: CP14Knowledge
|
||||
id: Glasswork
|
||||
name: cp14-knowledge-glasswork-name
|
||||
desc: cp14-knowledge-glasswork-desc
|
||||
|
||||
# T1
|
||||
|
||||
- type: CP14Knowledge
|
||||
id: ClothingSewing
|
||||
name: cp14-knowledge-sewing-name
|
||||
desc: cp14-knowledge-sewing-desc
|
||||
|
||||
- type: CP14Knowledge
|
||||
id: WallpaperCraft
|
||||
name: cp14-knowledge-wallpaper-name
|
||||
desc: cp14-knowledge-wallpaper-desc
|
||||
|
||||
# T2
|
||||
|
||||
- type: CP14Knowledge
|
||||
id: AdvancedClothingSewing
|
||||
name: cp14-knowledge-sewing2-name
|
||||
desc: cp14-knowledge-sewing2-desc
|
||||
dependencies:
|
||||
- ClothingSewing
|
||||
@@ -1,4 +0,0 @@
|
||||
- type: roleLoadout
|
||||
id: CP14VampireSpells
|
||||
groups:
|
||||
- CP14GeneralSpells
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user