Merge branch 'master' into ed-12-05-2025-upstream
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
using Content.Client._CP14.JoinQueue;
|
||||
using Content.Shared._CP14.JoinQueue;
|
||||
using Robust.Client.Audio;
|
||||
using Robust.Client.Console;
|
||||
|
||||
@@ -27,5 +27,5 @@ public sealed partial class CP14LocalizationVisualsComponent : Component
|
||||
///
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public Dictionary<string, Dictionary<string, string>> MapStates;
|
||||
public Dictionary<string, Dictionary<string, string>> MapStates = new();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<Control xmlns="https://spacestation14.io">
|
||||
<Button Name="Button">
|
||||
<GridContainer Columns="2">
|
||||
<TextureRect Name="View"
|
||||
Stretch="KeepAspectCentered"
|
||||
Margin="0,0,4,0"
|
||||
MinSize="48 48"
|
||||
MaxSize="48 48"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalExpand="True" />
|
||||
<Label Name="Name" />
|
||||
</GridContainer>
|
||||
</Button>
|
||||
</Control>
|
||||
@@ -0,0 +1,60 @@
|
||||
using Content.Shared._CP14.Skill;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._CP14.ResearchTable;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CP14ResearchRecipeControl : Control
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entity = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
|
||||
public event Action<CP14ResearchUiEntry, CP14SkillPrototype>? OnResearch;
|
||||
|
||||
private readonly SpriteSystem _sprite;
|
||||
private readonly CP14SharedSkillSystem _skillSystem;
|
||||
|
||||
private readonly CP14SkillPrototype _skillPrototype;
|
||||
private readonly bool _craftable;
|
||||
|
||||
public CP14ResearchRecipeControl(CP14ResearchUiEntry entry)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_sprite = _entity.System<SpriteSystem>();
|
||||
_skillSystem = _entity.System<CP14SharedSkillSystem>();
|
||||
|
||||
_skillPrototype = _prototype.Index(entry.ProtoId);
|
||||
_craftable = entry.Craftable;
|
||||
|
||||
Button.OnPressed += _ => OnResearch?.Invoke(entry, _skillPrototype);
|
||||
|
||||
UpdateColor();
|
||||
UpdateName();
|
||||
UpdateView();
|
||||
}
|
||||
|
||||
private void UpdateColor()
|
||||
{
|
||||
if (_craftable)
|
||||
return;
|
||||
|
||||
Button.ModulateSelfOverride = Color.FromHex("#302622");
|
||||
}
|
||||
|
||||
private void UpdateName()
|
||||
{
|
||||
Name.Text = $"{Loc.GetString(_skillSystem.GetSkillName(_skillPrototype))}" ;
|
||||
}
|
||||
|
||||
private void UpdateView()
|
||||
{
|
||||
View.Texture =_sprite.Frame0(_skillPrototype.Icon);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using Content.Shared._CP14.Skill;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client._CP14.ResearchTable;
|
||||
|
||||
public sealed class CP14ResearchTableBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
private CP14ResearchTableWindow? _window;
|
||||
|
||||
public CP14ResearchTableBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_window = this.CreateWindow<CP14ResearchTableWindow>();
|
||||
|
||||
_window.OnResearch += entry => SendMessage(new CP14ResearchMessage(entry.ProtoId));
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case CP14ResearchTableUiState recipesState:
|
||||
_window?.UpdateState(recipesState);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<DefaultWindow xmlns="https://spacestation14.io"
|
||||
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
Title="{Loc 'cp14-research-table-title'}"
|
||||
SetSize="700 500"
|
||||
MinSize="700 300">
|
||||
<BoxContainer Orientation="Horizontal">
|
||||
<!-- Main -->
|
||||
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Horizontal">
|
||||
<!-- Product list (left side UI) -->
|
||||
<BoxContainer MinWidth="350" HorizontalExpand="True" Orientation="Vertical" Margin="0 0 10 0">
|
||||
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
|
||||
<!-- Search Bar -->
|
||||
<LineEdit Name="SearchBar" Margin="4" PlaceHolder="Search" HorizontalExpand="True" />
|
||||
<OptionButton Name="OptionCategories" Access="Public" MinSize="130 0" />
|
||||
</BoxContainer>
|
||||
<!-- Crafts container -->
|
||||
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" MinSize="0 200">
|
||||
<BoxContainer Name="CraftsContainer" Orientation="Vertical" HorizontalExpand="True" />
|
||||
</ScrollContainer>
|
||||
</BoxContainer>
|
||||
|
||||
<!-- Craft view (right side UI) -->
|
||||
<BoxContainer MinWidth="350" Orientation="Vertical" HorizontalExpand="True"
|
||||
VerticalExpand="True">
|
||||
<PanelContainer HorizontalExpand="True" VerticalExpand="True">
|
||||
<!-- Background -->
|
||||
<PanelContainer.PanelOverride>
|
||||
<graphics:StyleBoxFlat BackgroundColor="#41332f" />
|
||||
</PanelContainer.PanelOverride>
|
||||
|
||||
<!-- Content -->
|
||||
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Vertical">
|
||||
<!-- Item info -->
|
||||
<!-- icon -->
|
||||
<TextureRect Name="ItemView"
|
||||
Stretch="KeepAspectCentered"
|
||||
Margin="5"
|
||||
MinSize="64 64"
|
||||
MaxSize="64 64"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<!-- name & description -->
|
||||
<BoxContainer Margin="5 0 0 0" HorizontalExpand="True" VerticalExpand="True"
|
||||
Orientation="Vertical">
|
||||
<RichTextLabel Name="ItemName" Margin="5" />
|
||||
<RichTextLabel Name="ItemDescription" Margin="5" />
|
||||
</BoxContainer>
|
||||
|
||||
<controls:HLine Color="#404040" Thickness="2" Margin="0 5" />
|
||||
|
||||
<!-- Required title -->
|
||||
<Label Margin="5 0 0 0" Text="{Loc 'cp14-research-recipe-list'}" />
|
||||
|
||||
<!-- Craft requirements content -->
|
||||
<!-- Added by code -->
|
||||
<BoxContainer
|
||||
Margin="5 0 0 0"
|
||||
Name="ItemRequirements"
|
||||
Orientation="Vertical" VerticalExpand="True"
|
||||
HorizontalExpand="True" />
|
||||
|
||||
<controls:HLine Color="#404040" Thickness="5" Margin="0 5" />
|
||||
|
||||
<!-- Craft button -->
|
||||
<Button Name="CraftButton" Text="{Loc 'cp14-research-craft'}" />
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
@@ -0,0 +1,235 @@
|
||||
using Content.Client._CP14.Workbench;
|
||||
using Content.Shared._CP14.Skill;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared._CP14.Skill.Restrictions;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._CP14.ResearchTable;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CP14ResearchTableWindow : DefaultWindow
|
||||
{
|
||||
private const int AllCategoryId = -1;
|
||||
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly ILogManager _log = default!;
|
||||
[Dependency] private readonly IEntityManager _entity = default!;
|
||||
|
||||
private readonly SpriteSystem _sprite;
|
||||
private readonly CP14SharedSkillSystem _skillSystem;
|
||||
|
||||
public event Action<CP14ResearchUiEntry>? OnResearch;
|
||||
|
||||
private readonly Dictionary<int, LocId> _categories = new();
|
||||
|
||||
private CP14ResearchTableUiState? _cachedState;
|
||||
private CP14ResearchUiEntry? _selectedEntry;
|
||||
private string _searchFilter = string.Empty;
|
||||
|
||||
private ISawmill Sawmill { get; init; }
|
||||
|
||||
public CP14ResearchTableWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_sprite = _entity.System<SpriteSystem>();
|
||||
_skillSystem = _entity.System<CP14SharedSkillSystem>();
|
||||
|
||||
Sawmill = _log.GetSawmill("cp14_research_table_window");
|
||||
|
||||
SearchBar.OnTextChanged += OnSearchChanged;
|
||||
CraftButton.OnPressed += OnCraftPressed;
|
||||
OptionCategories.OnItemSelected += OnCategoryItemSelected;
|
||||
}
|
||||
|
||||
public void UpdateRecipesVisibility()
|
||||
{
|
||||
if (_cachedState is null)
|
||||
return;
|
||||
|
||||
CraftsContainer.RemoveAllChildren();
|
||||
|
||||
var recipes = new List<CP14ResearchUiEntry>();
|
||||
foreach (var entry in _cachedState.Skills)
|
||||
{
|
||||
if (!_prototype.TryIndex(entry.ProtoId, out var indexedEntry))
|
||||
{
|
||||
Sawmill.Error($"No recipe prototype {entry.ProtoId} retrieved from cache found");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!ProcessSearchFilter(indexedEntry))
|
||||
continue;
|
||||
|
||||
if (!ProcessSearchCategoryFilter(indexedEntry))
|
||||
continue;
|
||||
|
||||
recipes.Add(entry);
|
||||
}
|
||||
|
||||
recipes.Sort(CP14ResearchUiEntry.CompareTo);
|
||||
|
||||
foreach (var recipe in recipes)
|
||||
{
|
||||
var control = new CP14ResearchRecipeControl(recipe);
|
||||
control.OnResearch += RecipeSelect;
|
||||
|
||||
CraftsContainer.AddChild(control);
|
||||
}
|
||||
|
||||
if (_selectedEntry is not null && !recipes.Contains(_selectedEntry.Value))
|
||||
RecipeSelectNull();
|
||||
}
|
||||
|
||||
public void UpdateState(CP14ResearchTableUiState recipesState)
|
||||
{
|
||||
_cachedState = recipesState;
|
||||
|
||||
_categories.Clear();
|
||||
OptionCategories.Clear();
|
||||
OptionCategories.AddItem(Loc.GetString("cp14-recipe-category-all"), AllCategoryId);
|
||||
|
||||
var categories = new List<LocId>();
|
||||
var count = 0;
|
||||
|
||||
foreach (var skill in recipesState.Skills)
|
||||
{
|
||||
if (!_prototype.TryIndex(skill.ProtoId, out var indexedSkill))
|
||||
continue;
|
||||
|
||||
if (!_prototype.TryIndex(indexedSkill.Tree, out var indexedTree))
|
||||
continue;
|
||||
|
||||
if (categories.Contains(indexedTree.Name))
|
||||
continue;
|
||||
|
||||
categories.Add(indexedTree.Name);
|
||||
}
|
||||
|
||||
categories.Sort((a, b) => string.Compare(Loc.GetString(a), Loc.GetString(b), StringComparison.Ordinal));
|
||||
|
||||
foreach (var category in categories)
|
||||
{
|
||||
OptionCategories.AddItem(Loc.GetString(category), count);
|
||||
_categories.Add(count, category);
|
||||
count++;
|
||||
}
|
||||
|
||||
UpdateRecipesVisibility();
|
||||
}
|
||||
|
||||
private void OnSearchChanged(LineEdit.LineEditEventArgs _)
|
||||
{
|
||||
_searchFilter = SearchBar.Text.Trim().ToLowerInvariant();
|
||||
UpdateRecipesVisibility();
|
||||
}
|
||||
|
||||
private void OnCraftPressed(BaseButton.ButtonEventArgs _)
|
||||
{
|
||||
if (_selectedEntry is null)
|
||||
return;
|
||||
|
||||
OnResearch?.Invoke(_selectedEntry.Value);
|
||||
}
|
||||
|
||||
private void OnCategoryItemSelected(OptionButton.ItemSelectedEventArgs obj)
|
||||
{
|
||||
OptionCategories.SelectId(obj.Id);
|
||||
UpdateRecipesVisibility();
|
||||
}
|
||||
|
||||
private bool ProcessSearchFilter(CP14SkillPrototype indexedEntry)
|
||||
{
|
||||
if (_searchFilter == string.Empty)
|
||||
return true;
|
||||
|
||||
return Loc.GetString(_skillSystem.GetSkillName(indexedEntry)).Contains(_searchFilter);
|
||||
}
|
||||
|
||||
private bool ProcessSearchCategoryFilter(CP14SkillPrototype indexedEntry)
|
||||
{
|
||||
// If we are searching through all categories, we simply skip the current filter
|
||||
if (OptionCategories.SelectedId == AllCategoryId)
|
||||
return true;
|
||||
|
||||
if (!_categories.TryGetValue(OptionCategories.SelectedId, out var selectedCategory))
|
||||
{
|
||||
Sawmill.Error($"Non-existent {OptionCategories.SelectedId} category id selected. Filter skipped");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!_prototype.TryIndex(indexedEntry.Tree, out var indexedTree))
|
||||
{
|
||||
Sawmill.Error($"Non-existent {indexedEntry.Tree} category prototype id. Filter skipped");
|
||||
return true;
|
||||
}
|
||||
|
||||
return indexedTree.Name == selectedCategory;
|
||||
}
|
||||
|
||||
private void RecipeSelect(CP14ResearchTableUiState recipesState)
|
||||
{
|
||||
foreach (var skill in recipesState.Skills)
|
||||
{
|
||||
RecipeSelect(skill, _prototype.Index(skill.ProtoId));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void RecipeSelect(CP14ResearchUiEntry cachedEntry)
|
||||
{
|
||||
if (_cachedState is null)
|
||||
return;
|
||||
|
||||
if (_cachedState.Skills.Contains(cachedEntry))
|
||||
{
|
||||
Sawmill.Warning($"The selected cache option {cachedEntry} isn't found in recipes");
|
||||
return;
|
||||
}
|
||||
|
||||
RecipeSelect(cachedEntry, _prototype.Index(cachedEntry.ProtoId));
|
||||
}
|
||||
|
||||
private void RecipeSelect(CP14ResearchUiEntry entry, CP14SkillPrototype skill)
|
||||
{
|
||||
_selectedEntry = entry;
|
||||
|
||||
ItemView.Texture = _sprite.Frame0(skill.Icon);
|
||||
ItemName.Text = _skillSystem.GetSkillName(skill);
|
||||
ItemDescription.Text = _skillSystem.GetSkillDescription(skill);
|
||||
ItemRequirements.RemoveAllChildren();
|
||||
|
||||
foreach (var restriction in skill.Restrictions)
|
||||
{
|
||||
switch (restriction)
|
||||
{
|
||||
case Researched researched:
|
||||
foreach (var requirement in researched.Requirements)
|
||||
{
|
||||
ItemRequirements.AddChild(new CP14WorkbenchRequirementControl(requirement));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CraftButton.Disabled = !entry.Craftable;
|
||||
}
|
||||
|
||||
private void RecipeSelectNull()
|
||||
{
|
||||
_selectedEntry = null;
|
||||
|
||||
ItemView.Texture = null;
|
||||
ItemName.Text = string.Empty;
|
||||
ItemDescription.Text = string.Empty;
|
||||
ItemRequirements.RemoveAllChildren();
|
||||
CraftButton.Disabled = true;
|
||||
}
|
||||
}
|
||||
@@ -7,13 +7,9 @@
|
||||
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 Orientation="Horizontal" HorizontalExpand="True" HorizontalAlignment="Right">
|
||||
<TextureRect Name="SkillPointImage" VerticalAlignment="Center" Visible="False" HorizontalAlignment="Center" Margin="0 0 8 0" TextureScale="2, 2" TexturePath="/Textures/_CP14/Interface/Misc/skillpoint.png"/>
|
||||
<Label Name="SkillTreeLabel" Margin="-5 0 0 0"/>
|
||||
</BoxContainer>
|
||||
</Button>
|
||||
<PanelContainer Name="ColorPanel"
|
||||
|
||||
@@ -10,12 +10,21 @@ public sealed partial class CP14SkillTreeButtonControl : Control
|
||||
{
|
||||
public event Action? OnPressed;
|
||||
|
||||
public CP14SkillTreeButtonControl(Color color, string label)
|
||||
public CP14SkillTreeButtonControl(Color color, string label, float skillpoints)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
|
||||
ColorPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = color };
|
||||
SkillTreeLabel.Text = label;
|
||||
if (skillpoints > 0)
|
||||
{
|
||||
SkillPointImage.Visible = true;
|
||||
SkillTreeLabel.Text = $"{skillpoints} {label}";
|
||||
}
|
||||
else
|
||||
{
|
||||
SkillPointImage.Visible = false;
|
||||
SkillTreeLabel.Text = $"{label}";
|
||||
}
|
||||
|
||||
MainButton.OnPressed += args => OnPressed?.Invoke();
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ public sealed class CP14SkillUIController : UIController, IOnStateEntered<Gamepl
|
||||
private EntityUid? _targetPlayer;
|
||||
|
||||
private IEnumerable<CP14SkillPrototype> _allSkills = [];
|
||||
private IEnumerable<CP14SkillTreePrototype> _allTrees = [];
|
||||
|
||||
private CP14SkillPrototype? _selectedSkill;
|
||||
private CP14SkillTreePrototype? _selectedSkillTree;
|
||||
@@ -70,9 +71,9 @@ public sealed class CP14SkillUIController : UIController, IOnStateEntered<Gamepl
|
||||
private void CacheSkillProto()
|
||||
{
|
||||
_allSkills = _proto.EnumeratePrototypes<CP14SkillPrototype>();
|
||||
_allTrees = _proto.EnumeratePrototypes<CP14SkillTreePrototype>().OrderBy(tree => Loc.GetString(tree.Name));
|
||||
}
|
||||
|
||||
|
||||
public void OnStateExited(GameplayState state)
|
||||
{
|
||||
if (_window != null)
|
||||
@@ -135,7 +136,7 @@ public sealed class CP14SkillUIController : UIController, IOnStateEntered<Gamepl
|
||||
if (_window is null)
|
||||
return;
|
||||
|
||||
if (_playerManager.LocalEntity == null)
|
||||
if (_targetPlayer == null)
|
||||
return;
|
||||
|
||||
if (node == null)
|
||||
@@ -158,7 +159,7 @@ public sealed class CP14SkillUIController : UIController, IOnStateEntered<Gamepl
|
||||
if (_window is null)
|
||||
return;
|
||||
|
||||
if (_playerManager.LocalEntity == null)
|
||||
if (_targetPlayer == null)
|
||||
return;
|
||||
|
||||
_selectedSkill = skill;
|
||||
@@ -171,8 +172,9 @@ public sealed class CP14SkillUIController : UIController, IOnStateEntered<Gamepl
|
||||
{
|
||||
_window.SkillName.Text = _skill.GetSkillName(skill);
|
||||
_window.SkillDescription.SetMessage(GetSkillDescription(skill));
|
||||
_window.SkillFree.Visible = _skill.HaveFreeSkill(_targetPlayer.Value, skill);
|
||||
_window.SkillView.Texture = skill.Icon.Frame0();
|
||||
_window.LearnButton.Disabled = !_skill.CanLearnSkill(_playerManager.LocalEntity.Value, skill);
|
||||
_window.LearnButton.Disabled = !_skill.CanLearnSkill(_targetPlayer.Value, skill);
|
||||
_window.SkillCost.Text = skill.LearnCost.ToString();
|
||||
}
|
||||
|
||||
@@ -186,6 +188,7 @@ public sealed class CP14SkillUIController : UIController, IOnStateEntered<Gamepl
|
||||
|
||||
_window.SkillName.Text = string.Empty;
|
||||
_window.SkillDescription.Text = string.Empty;
|
||||
_window.SkillFree.Visible = false;
|
||||
_window.SkillView.Texture = null;
|
||||
_window.LearnButton.Disabled = true;
|
||||
}
|
||||
@@ -194,7 +197,7 @@ public sealed class CP14SkillUIController : UIController, IOnStateEntered<Gamepl
|
||||
{
|
||||
var msg = new FormattedMessage();
|
||||
|
||||
if (_playerManager.LocalEntity == null)
|
||||
if (_targetPlayer == null)
|
||||
return msg;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
@@ -202,12 +205,15 @@ public sealed class CP14SkillUIController : UIController, IOnStateEntered<Gamepl
|
||||
//Description
|
||||
sb.Append(_skill.GetSkillDescription(skill) + "\n \n");
|
||||
|
||||
//Restrictions
|
||||
foreach (var req in skill.Restrictions)
|
||||
if (!_skill.HaveSkill(_targetPlayer.Value, skill))
|
||||
{
|
||||
var color = req.Check(_entManager, _playerManager.LocalEntity.Value) ? "green" : "red";
|
||||
//Restrictions
|
||||
foreach (var req in skill.Restrictions)
|
||||
{
|
||||
var color = req.Check(_entManager, _targetPlayer.Value, skill) ? "green" : "red";
|
||||
|
||||
sb.Append($"- [color={color}]{req.GetDescription(_entManager, _proto)}[/color]\n");
|
||||
sb.Append($"- [color={color}]{req.GetDescription(_entManager, _proto)}[/color]\n");
|
||||
}
|
||||
}
|
||||
|
||||
msg.TryAddMarkup(sb.ToString(), out _);
|
||||
@@ -284,14 +290,11 @@ public sealed class CP14SkillUIController : UIController, IOnStateEntered<Gamepl
|
||||
return;
|
||||
|
||||
//If tree not selected, select the first one
|
||||
if (_selectedSkillTree == null && storage.Progress.Count > 0)
|
||||
if (_selectedSkillTree == null)
|
||||
{
|
||||
var firstTree = storage.Progress.First().Key;
|
||||
var firstTree = _allTrees.First();
|
||||
|
||||
if (_proto.TryIndex(firstTree, out var indexedTree))
|
||||
{
|
||||
SelectTree(indexedTree, storage); // Set the first tree from the player's progress
|
||||
}
|
||||
SelectTree(firstTree, storage); // Set the first tree from the player's progress
|
||||
}
|
||||
|
||||
if (_selectedSkillTree == null)
|
||||
@@ -301,26 +304,28 @@ public sealed class CP14SkillUIController : UIController, IOnStateEntered<Gamepl
|
||||
SelectNode(_selectedSkill);
|
||||
UpdateGraphControl();
|
||||
|
||||
// Update the experience points for the selected tree
|
||||
var playerProgress = storage.Progress;
|
||||
if (playerProgress.TryGetValue(_selectedSkillTree, out var skillPoint))
|
||||
{
|
||||
_window.ExpPointLabel.Text = skillPoint.ToString();
|
||||
}
|
||||
|
||||
_window.LevelLabel.Text = $"{storage.SkillsSumExperience}/{storage.ExperienceMaxCap}";
|
||||
|
||||
_window.TreeTabsContainer.RemoveAllChildren();
|
||||
foreach (var (tree, _) in storage.Progress)
|
||||
foreach (var tree in _allTrees)
|
||||
{
|
||||
if (!_proto.TryIndex(tree, out var indexedTree))
|
||||
continue;
|
||||
float learnedPoints = 0;
|
||||
foreach (var skillId in storage.LearnedSkills)
|
||||
{
|
||||
//TODO: Loop indexing each skill is bad
|
||||
if (_proto.TryIndex(skillId, out var skill) && skill.Tree == tree)
|
||||
{
|
||||
if (_skill.HaveFreeSkill(_targetPlayer.Value, skillId))
|
||||
continue;
|
||||
learnedPoints += skill.LearnCost;
|
||||
}
|
||||
}
|
||||
|
||||
var treeButton2 = new CP14SkillTreeButtonControl(indexedTree.Color, Loc.GetString(indexedTree.Name));
|
||||
treeButton2.ToolTip = Loc.GetString(indexedTree.Desc ?? string.Empty);
|
||||
var treeButton2 = new CP14SkillTreeButtonControl(tree.Color, Loc.GetString(tree.Name), learnedPoints);
|
||||
treeButton2.ToolTip = Loc.GetString(tree.Desc ?? string.Empty);
|
||||
treeButton2.OnPressed += () =>
|
||||
{
|
||||
SelectTree(indexedTree, storage);
|
||||
SelectTree(tree, storage);
|
||||
};
|
||||
|
||||
_window.TreeTabsContainer.AddChild(treeButton2);
|
||||
@@ -336,9 +341,6 @@ public sealed class CP14SkillUIController : UIController, IOnStateEntered<Gamepl
|
||||
_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";
|
||||
|
||||
UpdateGraphControl();
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
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"
|
||||
xmlns:nodeTree="clr-namespace:Content.Client._CP14.UserInterface.Systems.NodeTree"
|
||||
Title="{Loc 'cp14-skill-info-title'}"
|
||||
MinSize="700 350"
|
||||
@@ -46,6 +45,9 @@
|
||||
<BoxContainer HorizontalExpand="True">
|
||||
<RichTextLabel Name="SkillDescription" HorizontalExpand="True" Access="Public"/>
|
||||
</BoxContainer>
|
||||
<BoxContainer HorizontalExpand="True">
|
||||
<RichTextLabel Name="SkillFree" Text="{Loc 'cp14-skill-menu-free'}" HorizontalExpand="True" Access="Public" Visible="False"/>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</ScrollContainer>
|
||||
@@ -76,10 +78,6 @@
|
||||
</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/Misc/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/Misc/skillpoint.png"/>
|
||||
<RichTextLabel Margin="0 0 0 0" Name="LevelLabel" VerticalAlignment="Center" HorizontalAlignment="Left" Text="0" StyleClasses="LabelKeyText" Access="Public"/>
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
using Content.Shared._CP14.Workbench;
|
||||
using Content.Shared._CP14.Workbench.Prototypes;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface;
|
||||
@@ -13,37 +14,52 @@ using Robust.Shared.Prototypes;
|
||||
namespace Content.Client._CP14.Workbench;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CP14WorkbenchRequirementControl : Control
|
||||
public sealed partial class CP14WorkbenchRecipeControl : Control
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entity = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
|
||||
public event Action<CP14WorkbenchUiRecipesEntry, CP14WorkbenchRecipePrototype>? OnSelect;
|
||||
|
||||
private readonly SpriteSystem _sprite;
|
||||
|
||||
public CP14WorkbenchRequirementControl()
|
||||
private readonly CP14WorkbenchRecipePrototype _recipePrototype;
|
||||
private readonly bool _craftable;
|
||||
|
||||
public CP14WorkbenchRecipeControl(CP14WorkbenchUiRecipesEntry entry)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_sprite = _entity.System<SpriteSystem>();
|
||||
|
||||
_recipePrototype = _prototype.Index(entry.ProtoId);
|
||||
_craftable = entry.Craftable;
|
||||
|
||||
Button.OnPressed += _ => OnSelect?.Invoke(entry, _recipePrototype);
|
||||
|
||||
UpdateColor();
|
||||
UpdateName();
|
||||
UpdateView();
|
||||
}
|
||||
|
||||
public CP14WorkbenchRequirementControl(CP14WorkbenchCraftRequirement requirement) : this()
|
||||
private void UpdateColor()
|
||||
{
|
||||
Name.Text = requirement.GetRequirementTitle(_proto);
|
||||
if (_craftable)
|
||||
return;
|
||||
|
||||
var texture = requirement.GetRequirementTexture(_proto);
|
||||
if (texture is not null)
|
||||
{
|
||||
View.Visible = true;
|
||||
View.Texture = _sprite.Frame0(texture);
|
||||
}
|
||||
Button.ModulateSelfOverride = Color.FromHex("#302622");
|
||||
}
|
||||
|
||||
var entityView = requirement.GetRequirementEntityView(_proto);
|
||||
if (entityView is not null)
|
||||
{
|
||||
EntityView.Visible = true;
|
||||
EntityView.SetPrototype(entityView);
|
||||
}
|
||||
private void UpdateName()
|
||||
{
|
||||
var result = _prototype.Index(_recipePrototype.Result);
|
||||
var counter = _recipePrototype.ResultCount > 1 ? $" x{_recipePrototype.ResultCount}" : "";
|
||||
Name.Text = $"{Loc.GetString(result.Name)} {counter}" ;
|
||||
}
|
||||
|
||||
private void UpdateView()
|
||||
{
|
||||
View.SetPrototype(_recipePrototype.Result);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is sublicensed under MIT License
|
||||
* https://github.com/space-wizards/space-station-14/blob/master/LICENSE.TXT
|
||||
*/
|
||||
|
||||
using Content.Shared._CP14.Workbench;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._CP14.Workbench;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CP14WorkbenchRequirementControl : Control
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entity = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
private readonly SpriteSystem _sprite;
|
||||
|
||||
public CP14WorkbenchRequirementControl()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_sprite = _entity.System<SpriteSystem>();
|
||||
}
|
||||
|
||||
public CP14WorkbenchRequirementControl(CP14WorkbenchCraftRequirement requirement) : this()
|
||||
{
|
||||
Name.Text = requirement.GetRequirementTitle(_proto);
|
||||
|
||||
var texture = requirement.GetRequirementTexture(_proto);
|
||||
if (texture is not null)
|
||||
{
|
||||
View.Visible = true;
|
||||
View.Texture = _sprite.Frame0(texture);
|
||||
}
|
||||
|
||||
var entityView = requirement.GetRequirementEntityView(_proto);
|
||||
if (entityView is not null)
|
||||
{
|
||||
EntityView.Visible = true;
|
||||
EntityView.SetPrototype(entityView);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* This file is sublicensed under MIT License
|
||||
* https://github.com/space-wizards/space-station-14/blob/master/LICENSE.TXT
|
||||
*/
|
||||
|
||||
using Content.Shared._CP14.Workbench;
|
||||
using Content.Shared._CP14.Workbench.Prototypes;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._CP14.Workbench;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CP14WorkbenchRecipeControl : Control
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entity = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
|
||||
public event Action<CP14WorkbenchUiRecipesEntry, CP14WorkbenchRecipePrototype>? OnSelect;
|
||||
|
||||
private readonly SpriteSystem _sprite;
|
||||
|
||||
private readonly CP14WorkbenchRecipePrototype _recipePrototype;
|
||||
private readonly bool _craftable;
|
||||
|
||||
public CP14WorkbenchRecipeControl(CP14WorkbenchUiRecipesEntry entry)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_sprite = _entity.System<SpriteSystem>();
|
||||
|
||||
_recipePrototype = _prototype.Index(entry.ProtoId);
|
||||
_craftable = entry.Craftable;
|
||||
|
||||
Button.OnPressed += _ => OnSelect?.Invoke(entry, _recipePrototype);
|
||||
|
||||
UpdateColor();
|
||||
UpdateName();
|
||||
UpdateView();
|
||||
}
|
||||
|
||||
private void UpdateColor()
|
||||
{
|
||||
if (_craftable)
|
||||
return;
|
||||
|
||||
Button.ModulateSelfOverride = Color.FromHex("#302622");
|
||||
}
|
||||
|
||||
private void UpdateName()
|
||||
{
|
||||
var result = _prototype.Index(_recipePrototype.Result);
|
||||
var counter = _recipePrototype.ResultCount > 1 ? $" x{_recipePrototype.ResultCount}" : "";
|
||||
Name.Text = $"{Loc.GetString(result.Name)} {counter}" ;
|
||||
}
|
||||
|
||||
private void UpdateView()
|
||||
{
|
||||
View.SetPrototype(_recipePrototype.Result);
|
||||
}
|
||||
}
|
||||
@@ -35,9 +35,9 @@
|
||||
<!-- icon -->
|
||||
<EntityPrototypeView Name="ItemView"
|
||||
Scale="2,2"
|
||||
Margin="0,0,4,0"
|
||||
MinSize="64 64"
|
||||
MaxSize="64 64"
|
||||
Margin="8"
|
||||
MinSize="96 96"
|
||||
MaxSize="96 96"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
<!-- name & description -->
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
namespace Content.Client._CP14.WorldSprite;
|
||||
|
||||
/// <summary>
|
||||
/// RUN, IF YOU SEE THE CODE TO THIS FUCKING THING, YOU'LL DIE ON THE SPOT.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14WorldSpriteComponent : Component
|
||||
{
|
||||
public bool Inited;
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
using Content.Shared._CP14.WorldSprite;
|
||||
using Content.Shared.Throwing;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Map.Components;
|
||||
|
||||
namespace Content.Client._CP14.WorldSprite;
|
||||
|
||||
public sealed class CP14WorldSpriteSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AppearanceSystem _appearance = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
#if DEBUG
|
||||
SubscribeLocalEvent<CP14WorldSpriteComponent, ComponentInit>(OnComponentInit);
|
||||
#endif
|
||||
|
||||
SubscribeLocalEvent<CP14WorldSpriteComponent, EntParentChangedMessage>(OnParentChanged);
|
||||
SubscribeLocalEvent<CP14WorldSpriteComponent, ThrownEvent>(OnThrown);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<CP14WorldSpriteComponent>();
|
||||
while (query.MoveNext(out var uid, out var worldSpriteComponent))
|
||||
{
|
||||
if (worldSpriteComponent.Inited)
|
||||
continue;
|
||||
|
||||
Update(uid);
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
private void OnComponentInit(Entity<CP14WorldSpriteComponent> entity, ref ComponentInit args)
|
||||
{
|
||||
if (!HasComp<AppearanceComponent>(entity))
|
||||
Log.Error($"Requires an {nameof(AppearanceComponent)} for {entity}");
|
||||
}
|
||||
#endif
|
||||
|
||||
private void OnParentChanged(Entity<CP14WorldSpriteComponent> entity, ref EntParentChangedMessage args)
|
||||
{
|
||||
Update(entity);
|
||||
}
|
||||
|
||||
private void OnThrown(Entity<CP14WorldSpriteComponent> entity, ref ThrownEvent args)
|
||||
{
|
||||
// Idk, but throw don't call reparent
|
||||
Update(entity, args.User);
|
||||
}
|
||||
|
||||
private void Update(EntityUid entity, EntityUid? parent = null)
|
||||
{
|
||||
parent ??= Transform(entity).ParentUid;
|
||||
|
||||
var inWorld = HasComp<MapComponent>(parent) || HasComp<MapGridComponent>(parent);
|
||||
|
||||
_appearance.SetData(entity, WorldSpriteVisualLayers.Layer, inWorld);
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ public sealed partial class ChatSystem : SharedChatSystem
|
||||
public const int VoiceRange = 10; // how far voice goes in world units
|
||||
public const int WhisperClearRange = 2; // how far whisper goes while still being understandable, in world units
|
||||
public const int WhisperMuffledRange = 5; // how far whisper goes at all, in world units
|
||||
public const string DefaultAnnouncementSound = "/Audio/Announcements/announce.ogg";
|
||||
public const string DefaultAnnouncementSound = "/Audio/_CP14/Announce/event_boom.ogg"; //CP14 replaced default sound
|
||||
|
||||
private bool _loocEnabled = true;
|
||||
private bool _deadLoocEnabled;
|
||||
|
||||
@@ -5,7 +5,6 @@ namespace Content.Server.Entry
|
||||
{
|
||||
public static string[] List => new[] {
|
||||
"CP14WaveShader", // CP14 Wave shader
|
||||
"CP14WorldSprite", // CP14 World Sprite
|
||||
"ConstructionGhost",
|
||||
"IconSmooth",
|
||||
"InteractionOutline",
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Content.Server._CP14.Objectives.Systems;
|
||||
using Content.Server._CP14.StealArea;
|
||||
using Content.Server.Objectives.Systems;
|
||||
using Content.Server.Thief.Systems;
|
||||
|
||||
@@ -8,7 +7,7 @@ namespace Content.Server.Objectives.Components;
|
||||
/// <summary>
|
||||
/// An abstract component that allows other systems to count adjacent objects as "stolen" when controlling other systems
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(StealConditionSystem), typeof(ThiefBeaconSystem), typeof(CP14CurrencyCollectConditionSystem), typeof(CP14StealAreaAutoJobConnectSystem))] //CP14 add currency condition access
|
||||
[RegisterComponent, Access(typeof(StealConditionSystem), typeof(ThiefBeaconSystem), typeof(CP14CurrencyCollectConditionSystem))]
|
||||
public sealed partial class StealAreaComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
|
||||
@@ -324,7 +324,7 @@ public sealed partial class BiomeSystem : SharedBiomeSystem
|
||||
|
||||
private bool CanLoad(EntityUid uid)
|
||||
{
|
||||
return !_ghostQuery.HasComp(uid) || _tags.HasTag(uid, AllowBiomeLoadingTag);
|
||||
return !_ghostQuery.HasComp(uid);// CP14 - Admin biome loading break mapping || _tags.HasTag(uid, AllowBiomeLoadingTag);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
|
||||
@@ -115,8 +115,6 @@ public sealed partial class CP14DemiplaneSystem
|
||||
demiplane = ev.Demiplane;
|
||||
}
|
||||
|
||||
_statistic.TrackAdd(generator.Comp.Statistic, 1);
|
||||
|
||||
if (demiplane is null)
|
||||
return;
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using Content.Server._CP14.Demiplane.Components;
|
||||
using Content.Server._CP14.RoundStatistic;
|
||||
using Content.Server.Chat.Managers;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.Flash;
|
||||
@@ -33,7 +32,6 @@ public sealed partial class CP14DemiplaneSystem : CP14SharedDemiplaneSystem
|
||||
[Dependency] private readonly FlashSystem _flash = default!;
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly CP14RoundStatTrackerSystem _statistic = default!;
|
||||
[Dependency] private readonly ChatSystem _chat = default!;
|
||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
using Content.Server._CP14.DemiplaneTraveling;
|
||||
using Content.Shared._CP14.Demiplane.Prototypes;
|
||||
using Content.Shared._CP14.RoundStatistic;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Demiplane.Components;
|
||||
@@ -17,9 +16,6 @@ public sealed partial class CP14DemiplaneDataComponent : Component
|
||||
[DataField]
|
||||
public List<ProtoId<CP14DemiplaneModifierPrototype>> SelectedModifiers = new();
|
||||
|
||||
[DataField]
|
||||
public ProtoId<CP14RoundStatTrackerPrototype> Statistic = "DemiplaneOpen";
|
||||
|
||||
[DataField]
|
||||
public List<EntProtoId> AutoRifts = new() { "CP14DemiplaneTimedRadiusPassway", "CP14DemiplanRiftCore" };
|
||||
}
|
||||
|
||||
@@ -236,7 +236,7 @@ public sealed partial class CP14StationDemiplaneMapSystem : CP14SharedStationDem
|
||||
new Vector2(specialPos.X, specialPos.Y),
|
||||
false,
|
||||
locationConfig: special.Location,
|
||||
modifiers: special.Modifiers
|
||||
modifiers: [..special.Modifiers]
|
||||
);
|
||||
grid[specialPos] = specialNode;
|
||||
specialPositions.Add(specialPos);
|
||||
@@ -315,8 +315,9 @@ public sealed partial class CP14StationDemiplaneMapSystem : CP14SharedStationDem
|
||||
var limits = new Dictionary<ProtoId<CP14DemiplaneModifierCategoryPrototype>, float>
|
||||
{
|
||||
{ "Danger", (node.Level + node.AdditionalLevel) * 0.2f },
|
||||
{ "GhostRoleDanger", node.Level * 0.2f },
|
||||
{ "GhostRoleDanger", 1f },
|
||||
{ "Reward", Math.Max(node.Level * 0.2f, 0.5f) },
|
||||
{ "Ore", Math.Max(node.Level * 0.2f, 0.5f) },
|
||||
{ "Fun", 1f },
|
||||
{ "Weather", 1f },
|
||||
{ "MapLight", 1f },
|
||||
|
||||
@@ -42,6 +42,7 @@ public sealed class DiscordAuthManager
|
||||
"1294276016117911594",
|
||||
"1278755078315970620",
|
||||
"1330772249644630157",
|
||||
"1274951101464051846",
|
||||
};
|
||||
|
||||
public event EventHandler<ICommonSession>? PlayerVerified;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared._CP14.DayCycle;
|
||||
using Content.Shared._CP14.Farming.Components;
|
||||
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||
|
||||
@@ -5,6 +6,7 @@ namespace Content.Server._CP14.Farming;
|
||||
|
||||
public sealed partial class CP14FarmingSystem
|
||||
{
|
||||
[Dependency] private readonly CP14DayCycleSystem _dayCycle = default!;
|
||||
private void InitializeResources()
|
||||
{
|
||||
SubscribeLocalEvent<CP14PlantEnergyFromLightComponent, CP14PlantUpdateEvent>(OnTakeEnergyFromLight);
|
||||
@@ -16,7 +18,7 @@ public sealed partial class CP14FarmingSystem
|
||||
private void OnTakeEnergyFromLight(Entity<CP14PlantEnergyFromLightComponent> regeneration, ref CP14PlantUpdateEvent args)
|
||||
{
|
||||
var gainEnergy = false;
|
||||
var daylight = true;//_dayCycle.UnderSunlight(regeneration);
|
||||
var daylight = _dayCycle.UnderSunlight(regeneration);
|
||||
|
||||
if (regeneration.Comp.Daytime && daylight)
|
||||
gainEnergy = true;
|
||||
|
||||
114
Content.Server/_CP14/GameTicking/Rules/CP14BloodMoonCurseRule.cs
Normal file
114
Content.Server/_CP14/GameTicking/Rules/CP14BloodMoonCurseRule.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using System.Linq;
|
||||
using Content.Server._CP14.GameTicking.Rules.Components;
|
||||
using Content.Server.Antag;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.GameTicking.Rules;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Server.Stunnable;
|
||||
using Content.Shared._CP14.BloodMoon;
|
||||
using Content.Shared._CP14.DayCycle;
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
using Content.Shared.Mobs;
|
||||
using Content.Shared.Popups;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server._CP14.GameTicking.Rules;
|
||||
|
||||
public sealed class CP14BloodMoonCurseRule : GameRuleSystem<CP14BloodMoonCurseRuleComponent>
|
||||
{
|
||||
[Dependency] private readonly AntagSelectionSystem _antag = default!;
|
||||
[Dependency] private readonly StunSystem _stun = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||
[Dependency] private readonly TransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _action = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14StartDayEvent>(OnStartDay);
|
||||
SubscribeLocalEvent<CP14BloodMoonCurseRuleComponent, AfterAntagEntitySelectedEvent>(AfterAntagEntitySelected);
|
||||
SubscribeLocalEvent<CP14BloodMoonCurseComponent, ExaminedEvent>(CurseExamined);
|
||||
}
|
||||
|
||||
private void CurseExamined(Entity<CP14BloodMoonCurseComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("cp14-bloodmoon-curse-examined"));
|
||||
}
|
||||
|
||||
private void AfterAntagEntitySelected(Entity<CP14BloodMoonCurseRuleComponent> ent, ref AfterAntagEntitySelectedEvent args)
|
||||
{
|
||||
SpawnAttachedTo(ent.Comp.CurseEffect, Transform(args.EntityUid).Coordinates);
|
||||
var curseComp = EnsureComp<CP14BloodMoonCurseComponent>(args.EntityUid);
|
||||
var effect = SpawnAttachedTo(curseComp.CurseEffect, Transform(args.EntityUid).Coordinates);
|
||||
curseComp.SpawnedEffect = effect;
|
||||
curseComp.CurseRule = ent;
|
||||
_transform.SetParent(effect, args.EntityUid);
|
||||
_action.AddAction(args.EntityUid, ref curseComp.ActionEntity, curseComp.Action);
|
||||
}
|
||||
|
||||
protected override void Started(EntityUid uid,
|
||||
CP14BloodMoonCurseRuleComponent component,
|
||||
GameRuleComponent gameRule,
|
||||
GameRuleStartedEvent args)
|
||||
{
|
||||
Filter allPlayersInGame = Filter.Empty().AddWhere(GameTicker.UserHasJoinedGame);
|
||||
_chatSystem.DispatchFilteredAnnouncement(allPlayersInGame, Loc.GetString(component.StartAnnouncement), colorOverride: component.AnnouncementColor);
|
||||
|
||||
_audio.PlayGlobal(component.GlobalSound, allPlayersInGame, true);
|
||||
}
|
||||
|
||||
protected override void Ended(EntityUid uid,
|
||||
CP14BloodMoonCurseRuleComponent component,
|
||||
GameRuleComponent gameRule,
|
||||
GameRuleEndedEvent args)
|
||||
{
|
||||
Filter allPlayersInGame = Filter.Empty().AddWhere(GameTicker.UserHasJoinedGame);
|
||||
_chatSystem.DispatchFilteredAnnouncement(allPlayersInGame, Loc.GetString(component.EndAnnouncement), colorOverride: component.AnnouncementColor);
|
||||
|
||||
var aliveAntags = _antag.GetAliveAntags(uid);
|
||||
|
||||
foreach (var antag in aliveAntags)
|
||||
{
|
||||
SpawnAttachedTo(component.CurseEffect, Transform(antag).Coordinates);
|
||||
ClearCurse(antag);
|
||||
}
|
||||
|
||||
GameTicker.EndRound();
|
||||
}
|
||||
|
||||
private void OnStartDay(CP14StartDayEvent ev)
|
||||
{
|
||||
if (!HasComp<BecomesStationComponent>(ev.Map))
|
||||
return;
|
||||
|
||||
var query = QueryActiveRules();
|
||||
while (query.MoveNext(out var uid, out _, out var comp, out _))
|
||||
{
|
||||
ForceEndSelf(uid);
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearCurse(Entity<CP14BloodMoonCurseComponent?> ent)
|
||||
{
|
||||
if (!Resolve(ent.Owner, ref ent.Comp, false))
|
||||
return;
|
||||
|
||||
_stun.TryParalyze(ent, ent.Comp.EndStunDuration, true);
|
||||
_popup.PopupEntity(Loc.GetString("cp14-bloodmoon-curse-removed"), ent, PopupType.SmallCaution);
|
||||
if (TryComp<CP14BloodMoonCurseComponent>(ent, out var curseComp))
|
||||
{
|
||||
QueueDel(curseComp.SpawnedEffect);
|
||||
RemCompDeferred<CP14BloodMoonCurseComponent>(ent);
|
||||
}
|
||||
|
||||
_action.RemoveAction(ent.Comp.ActionEntity);
|
||||
}
|
||||
}
|
||||
54
Content.Server/_CP14/GameTicking/Rules/CP14BloodMoonRule.cs
Normal file
54
Content.Server/_CP14/GameTicking/Rules/CP14BloodMoonRule.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using Content.Server._CP14.GameTicking.Rules.Components;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.GameTicking.Rules;
|
||||
using Content.Server.Station.Components;
|
||||
using Content.Server.StationEvents.Events;
|
||||
using Content.Shared._CP14.DayCycle;
|
||||
using Content.Shared.GameTicking.Components;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server._CP14.GameTicking.Rules;
|
||||
|
||||
public sealed class CP14BloodMoonRule : GameRuleSystem<CP14BloodMoonRuleComponent>
|
||||
{
|
||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14StartNightEvent>(OnStartNight);
|
||||
}
|
||||
|
||||
protected override void Started(EntityUid uid,
|
||||
CP14BloodMoonRuleComponent component,
|
||||
GameRuleComponent gameRule,
|
||||
GameRuleStartedEvent args)
|
||||
{
|
||||
base.Started(uid, component, gameRule, args);
|
||||
|
||||
Filter allPlayersInGame = Filter.Empty().AddWhere(GameTicker.UserHasJoinedGame);
|
||||
_chatSystem.DispatchFilteredAnnouncement(
|
||||
allPlayersInGame,
|
||||
message: Loc.GetString(component.StartAnnouncement),
|
||||
colorOverride: component.AnnouncementColor);
|
||||
|
||||
_audio.PlayGlobal(component.AnnounceSound, allPlayersInGame, true);
|
||||
}
|
||||
|
||||
private void OnStartNight(CP14StartNightEvent ev)
|
||||
{
|
||||
if (!HasComp<BecomesStationComponent>(ev.Map))
|
||||
return;
|
||||
|
||||
var query = QueryActiveRules();
|
||||
while (query.MoveNext(out var uid, out _, out var comp, out _))
|
||||
{
|
||||
var ruleEnt = GameTicker.AddGameRule(comp.CurseRule);
|
||||
GameTicker.StartGameRule(ruleEnt);
|
||||
ForceEndSelf(uid);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.GameTicking.Rules.Components;
|
||||
|
||||
[RegisterComponent, Access(typeof(CP14BloodMoonCurseRule))]
|
||||
public sealed partial class CP14BloodMoonCurseRuleComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public LocId StartAnnouncement = "cp14-bloodmoon-start";
|
||||
|
||||
[DataField]
|
||||
public LocId EndAnnouncement = "cp14-bloodmoon-end";
|
||||
|
||||
[DataField]
|
||||
public Color? AnnouncementColor;
|
||||
|
||||
[DataField]
|
||||
public EntProtoId CurseEffect = "CP14ImpactEffectMagicSplitting";
|
||||
|
||||
[DataField]
|
||||
public SoundSpecifier GlobalSound = new SoundPathSpecifier("/Audio/_CP14/Ambience/blood_moon_raise.ogg")
|
||||
{
|
||||
Params = AudioParams.Default.WithVolume(-2f)
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.GameTicking.Rules.Components;
|
||||
|
||||
[RegisterComponent, Access(typeof(CP14BloodMoonRule))]
|
||||
public sealed partial class CP14BloodMoonRuleComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public EntProtoId CurseRule = "CP14BloodMoonCurseRule";
|
||||
|
||||
[DataField]
|
||||
public LocId StartAnnouncement = "cp14-bloodmoon-raising";
|
||||
|
||||
[DataField]
|
||||
public Color? AnnouncementColor = Color.FromHex("#e32759");
|
||||
|
||||
[DataField]
|
||||
public SoundSpecifier? AnnounceSound;
|
||||
}
|
||||
@@ -1,15 +1,16 @@
|
||||
using Content.Server._CP14.MagicEnergy.Components;
|
||||
using Content.Shared._CP14.DayCycle;
|
||||
using Content.Shared._CP14.MagicEnergy.Components;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Robust.Shared.Map.Components;
|
||||
|
||||
namespace Content.Server._CP14.MagicEnergy;
|
||||
|
||||
public partial class CP14MagicEnergySystem
|
||||
{
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly CP14DayCycleSystem _dayCycle = default!;
|
||||
|
||||
private void InitializeDraw()
|
||||
{
|
||||
@@ -75,16 +76,7 @@ public partial class CP14MagicEnergySystem
|
||||
|
||||
draw.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(draw.Delay);
|
||||
|
||||
var daylight = false;
|
||||
|
||||
//if (TryComp<MapLightComponent>(Transform(uid).MapUid, out var mapLight))
|
||||
//{
|
||||
// var color = mapLight.AmbientLightColor;
|
||||
// var medium = (color.R + color.G + color.B) / 3f;
|
||||
//
|
||||
// if (medium > draw.LightThreshold)
|
||||
// daylight = true;
|
||||
//}
|
||||
var daylight = _dayCycle.UnderSunlight(uid);
|
||||
|
||||
ChangeEnergy((uid, magicContainer), daylight ? draw.DaylightEnergy : draw.DarknessEnergy, out _, out _, true);
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
using Content.Server._CP14.Objectives.Systems;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server._CP14.Objectives.Components;
|
||||
|
||||
/// <summary>
|
||||
/// The player must be the richest among the players among the specified list of roles
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14RichestJobConditionSystem))]
|
||||
public sealed partial class CP14RichestJobConditionComponent : Component
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public ProtoId<JobPrototype> Job;
|
||||
|
||||
[DataField(required: true)]
|
||||
public LocId ObjectiveText;
|
||||
|
||||
[DataField(required: true)]
|
||||
public LocId ObjectiveDescription;
|
||||
|
||||
[DataField(required: true)]
|
||||
public SpriteSpecifier ObjectiveSprite;
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
using Content.Server._CP14.Objectives.Systems;
|
||||
using Content.Shared._CP14.RoundStatistic;
|
||||
using Content.Shared.Destructible.Thresholds;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server._CP14.Objectives.Components;
|
||||
|
||||
[RegisterComponent, Access(typeof(CP14StatisticRangeConditionSystem))]
|
||||
public sealed partial class CP14StatisticRangeConditionComponent : Component
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public ProtoId<CP14RoundStatTrackerPrototype> Statistic;
|
||||
|
||||
[DataField(required: true)]
|
||||
public MinMax Range;
|
||||
|
||||
[DataField(required: true)]
|
||||
public LocId ObjectiveText;
|
||||
|
||||
[DataField(required: true)]
|
||||
public LocId ObjectiveDescription;
|
||||
|
||||
[DataField(required: true)]
|
||||
public SpriteSpecifier? ObjectiveSprite;
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
using Content.Server._CP14.Objectives.Components;
|
||||
using Content.Shared._CP14.Currency;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Objectives.Components;
|
||||
using Content.Shared.Objectives.Systems;
|
||||
using Content.Shared.Roles.Jobs;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Objectives.Systems;
|
||||
|
||||
public sealed class CP14RichestJobConditionSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly SharedObjectivesSystem _objectives = default!;
|
||||
[Dependency] private readonly CP14SharedCurrencySystem _currency = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
[Dependency] private readonly SharedJobSystem _job = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14RichestJobConditionComponent, ObjectiveAfterAssignEvent>(OnCollectAfterAssign);
|
||||
SubscribeLocalEvent<CP14RichestJobConditionComponent, ObjectiveGetProgressEvent>(OnCollectGetProgress);
|
||||
}
|
||||
|
||||
private void OnCollectAfterAssign(Entity<CP14RichestJobConditionComponent> condition, ref ObjectiveAfterAssignEvent args)
|
||||
{
|
||||
if (!_proto.TryIndex(condition.Comp.Job, out var indexedJob))
|
||||
return;
|
||||
|
||||
_metaData.SetEntityName(condition.Owner, Loc.GetString(condition.Comp.ObjectiveText), args.Meta);
|
||||
_metaData.SetEntityDescription(condition.Owner, Loc.GetString(condition.Comp.ObjectiveDescription), args.Meta);
|
||||
_objectives.SetIcon(condition.Owner, condition.Comp.ObjectiveSprite);
|
||||
}
|
||||
|
||||
private void OnCollectGetProgress(Entity<CP14RichestJobConditionComponent> condition, ref ObjectiveGetProgressEvent args)
|
||||
{
|
||||
args.Progress = GetProgress(args.MindId, args.Mind, condition);
|
||||
}
|
||||
|
||||
private float GetProgress(EntityUid mindId, MindComponent mind, CP14RichestJobConditionComponent condition)
|
||||
{
|
||||
if (mind.OwnedEntity is null)
|
||||
return 0;
|
||||
|
||||
var ourValue = _currency.GetTotalCurrencyRecursive(mind.OwnedEntity.Value);
|
||||
var otherMaxValue = 0;
|
||||
|
||||
var allHumans = _mind.GetAliveHumans(mindId);
|
||||
if (allHumans.Count == 0)
|
||||
return 1; // No one to compare to, so we're the richest.
|
||||
|
||||
foreach (var otherHuman in allHumans)
|
||||
{
|
||||
if (!_job.MindTryGetJob(otherHuman, out var otherJob))
|
||||
continue;
|
||||
|
||||
if (otherJob != condition.Job)
|
||||
continue;
|
||||
|
||||
if (otherHuman.Comp.OwnedEntity is null)
|
||||
continue;
|
||||
|
||||
var otherValue = _currency.GetTotalCurrencyRecursive(otherHuman.Comp.OwnedEntity.Value);
|
||||
if (otherValue > otherMaxValue)
|
||||
otherMaxValue = otherValue;
|
||||
}
|
||||
|
||||
// if several players have the same amount of money, no one wins.
|
||||
return ourValue == otherMaxValue ? 0.99f : Math.Clamp(ourValue / (float)otherMaxValue, 0, 1);
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
using Content.Server._CP14.Objectives.Components;
|
||||
using Content.Server._CP14.RoundStatistic;
|
||||
using Content.Shared.Objectives.Components;
|
||||
using Content.Shared.Objectives.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._CP14.Objectives.Systems;
|
||||
|
||||
public sealed class CP14StatisticRangeConditionSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly SharedObjectivesSystem _objectives = default!;
|
||||
[Dependency] private readonly CP14RoundStatTrackerSystem _statistic = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14StatisticRangeConditionComponent, ObjectiveAfterAssignEvent>(OnAfterAssign);
|
||||
SubscribeLocalEvent<CP14StatisticRangeConditionComponent, ObjectiveGetProgressEvent>(OnGetProgress);
|
||||
}
|
||||
|
||||
private void OnAfterAssign(Entity<CP14StatisticRangeConditionComponent> condition, ref ObjectiveAfterAssignEvent args)
|
||||
{
|
||||
var title = Loc.GetString(condition.Comp.ObjectiveText,
|
||||
("min", condition.Comp.Range.Min),
|
||||
("max", condition.Comp.Range.Max));
|
||||
|
||||
var description = Loc.GetString(condition.Comp.ObjectiveDescription,
|
||||
("min", condition.Comp.Range.Min),
|
||||
("max", condition.Comp.Range.Max));
|
||||
|
||||
_metaData.SetEntityName(condition.Owner, title, args.Meta);
|
||||
_metaData.SetEntityDescription(condition.Owner, description, args.Meta);
|
||||
if (condition.Comp.ObjectiveSprite is not null)
|
||||
_objectives.SetIcon(condition.Owner, condition.Comp.ObjectiveSprite, args.Objective);
|
||||
}
|
||||
|
||||
private void OnGetProgress(Entity<CP14StatisticRangeConditionComponent> ent, ref ObjectiveGetProgressEvent args)
|
||||
{
|
||||
var statValue = _statistic.GetTrack(ent.Comp.Statistic);
|
||||
|
||||
if (statValue is null || statValue > ent.Comp.Range.Max || statValue < ent.Comp.Range.Min)
|
||||
{
|
||||
args.Progress = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
args.Progress = 1;
|
||||
}
|
||||
}
|
||||
199
Content.Server/_CP14/ResearchTable/CP14ResearchSystem.cs
Normal file
199
Content.Server/_CP14/ResearchTable/CP14ResearchSystem.cs
Normal file
@@ -0,0 +1,199 @@
|
||||
using Content.Server.DoAfter;
|
||||
using Content.Shared._CP14.ResearchTable;
|
||||
using Content.Shared._CP14.Skill;
|
||||
using Content.Shared._CP14.Skill.Components;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared._CP14.Skill.Restrictions;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.UserInterface;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.ResearchTable;
|
||||
|
||||
public sealed class CP14ResearchSystem : CP14SharedResearchSystem
|
||||
{
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _userInterface = default!;
|
||||
[Dependency] private readonly DoAfterSystem _doAfter = default!;
|
||||
[Dependency] private readonly AudioSystem _audio = default!;
|
||||
|
||||
private IEnumerable<CP14SkillPrototype> _allSkills = [];
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_allSkills = _proto.EnumeratePrototypes<CP14SkillPrototype>();
|
||||
|
||||
SubscribeLocalEvent<CP14ResearchTableComponent, BeforeActivatableUIOpenEvent>(OnBeforeUIOpen);
|
||||
SubscribeLocalEvent<CP14ResearchTableComponent, CP14ResearchMessage>(OnResearch);
|
||||
SubscribeLocalEvent<CP14ResearchTableComponent, CP14ResearchDoAfterEvent>(OnResearchEnd);
|
||||
|
||||
SubscribeLocalEvent<PrototypesReloadedEventArgs>(OnReloadPrototypes);
|
||||
}
|
||||
|
||||
private void OnReloadPrototypes(PrototypesReloadedEventArgs ev)
|
||||
{
|
||||
_allSkills = _proto.EnumeratePrototypes<CP14SkillPrototype>();
|
||||
}
|
||||
|
||||
private void OnResearchEnd(Entity<CP14ResearchTableComponent> table, ref CP14ResearchDoAfterEvent args)
|
||||
{
|
||||
if (args.Cancelled || args.Handled)
|
||||
return;
|
||||
|
||||
if (!_proto.TryIndex(args.Skill, out var indexedSkill))
|
||||
return;
|
||||
|
||||
var placedEntities = _lookup.GetEntitiesInRange(Transform(table).Coordinates,
|
||||
table.Comp.ResearchRadius,
|
||||
LookupFlags.Uncontained);
|
||||
|
||||
if (!CanResearch(indexedSkill, placedEntities, args.User))
|
||||
return;
|
||||
|
||||
if (!TryComp<CP14SkillStorageComponent>(args.User, out var storage))
|
||||
return;
|
||||
if (storage.ResearchedSkills.Contains(args.Skill) || storage.LearnedSkills.Contains(args.Skill))
|
||||
return;
|
||||
storage.ResearchedSkills.Add(args.Skill);
|
||||
Dirty(args.User, storage);
|
||||
|
||||
foreach (var restriction in indexedSkill.Restrictions)
|
||||
{
|
||||
switch (restriction)
|
||||
{
|
||||
case Researched researched:
|
||||
foreach (var req in researched.Requirements)
|
||||
{
|
||||
req.PostCraft(EntityManager, _proto, placedEntities, args.User);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_audio.PlayPvs(table.Comp.ResearchSound, table);
|
||||
UpdateUI(table, args.User);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void OnResearch(Entity<CP14ResearchTableComponent> ent, ref CP14ResearchMessage args)
|
||||
{
|
||||
if (!TryComp<CP14SkillStorageComponent>(args.Actor, out var storage))
|
||||
return;
|
||||
|
||||
if (storage.ResearchedSkills.Contains(args.Skill) || storage.LearnedSkills.Contains(args.Skill))
|
||||
return;
|
||||
|
||||
if (!_proto.TryIndex(args.Skill, out var indexedSkill))
|
||||
return;
|
||||
|
||||
StartResearch(ent, args.Actor, indexedSkill);
|
||||
}
|
||||
|
||||
private void OnBeforeUIOpen(Entity<CP14ResearchTableComponent> ent, ref BeforeActivatableUIOpenEvent args)
|
||||
{
|
||||
UpdateUI(ent, args.User);
|
||||
}
|
||||
|
||||
private void UpdateUI(Entity<CP14ResearchTableComponent> entity, EntityUid user)
|
||||
{
|
||||
var placedEntities = _lookup.GetEntitiesInRange(Transform(entity).Coordinates, entity.Comp.ResearchRadius);
|
||||
|
||||
if (!TryComp<CP14SkillStorageComponent>(user, out var storage))
|
||||
return;
|
||||
|
||||
var researches = new List<CP14ResearchUiEntry>();
|
||||
foreach (var skill in _allSkills)
|
||||
{
|
||||
var researchable = false;
|
||||
var canCraft = true;
|
||||
var hidden = false;
|
||||
|
||||
foreach (var restriction in skill.Restrictions)
|
||||
{
|
||||
if (storage.ResearchedSkills.Contains(skill) || storage.LearnedSkills.Contains(skill))
|
||||
continue;
|
||||
|
||||
switch (restriction)
|
||||
{
|
||||
case SpeciesWhitelist speciesWhitelist: //We cant change species of our character, so hide it
|
||||
if (!speciesWhitelist.Check(EntityManager, user, skill))
|
||||
hidden = true;
|
||||
break;
|
||||
|
||||
case NeedPrerequisite prerequisite:
|
||||
if (!storage.ResearchedSkills.Contains(prerequisite.Prerequisite))
|
||||
hidden = true;
|
||||
break;
|
||||
|
||||
case Researched researched:
|
||||
researchable = true;
|
||||
|
||||
foreach (var req in researched.Requirements)
|
||||
{
|
||||
if (!req.CheckRequirement(EntityManager, _proto, placedEntities, user))
|
||||
{
|
||||
canCraft = false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!researchable || hidden)
|
||||
continue;
|
||||
|
||||
var entry = new CP14ResearchUiEntry(skill, canCraft);
|
||||
|
||||
researches.Add(entry);
|
||||
}
|
||||
|
||||
_userInterface.SetUiState(entity.Owner, CP14ResearchTableUiKey.Key, new CP14ResearchTableUiState(researches));
|
||||
}
|
||||
|
||||
private void StartResearch(Entity<CP14ResearchTableComponent> table, EntityUid user, CP14SkillPrototype skill)
|
||||
{
|
||||
var researchDoAfter = new CP14ResearchDoAfterEvent()
|
||||
{
|
||||
Skill = skill
|
||||
};
|
||||
|
||||
var doAfterArgs = new DoAfterArgs(EntityManager,
|
||||
user,
|
||||
TimeSpan.FromSeconds(table.Comp.ResearchSpeed),
|
||||
researchDoAfter,
|
||||
table,
|
||||
table)
|
||||
{
|
||||
BreakOnMove = true,
|
||||
BreakOnDamage = true,
|
||||
NeedHand = true,
|
||||
};
|
||||
|
||||
_doAfter.TryStartDoAfter(doAfterArgs);
|
||||
_audio.PlayPvs(table.Comp.ResearchSound, table);
|
||||
}
|
||||
|
||||
private bool CanResearch(CP14SkillPrototype skill, HashSet<EntityUid> entities, EntityUid user)
|
||||
{
|
||||
foreach (var restriction in skill.Restrictions)
|
||||
{
|
||||
switch (restriction)
|
||||
{
|
||||
case Researched researched:
|
||||
foreach (var req in researched.Requirements)
|
||||
{
|
||||
if (!req.CheckRequirement(EntityManager, _proto, entities, user))
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
namespace Content.Server._CP14.RoleSalary;
|
||||
|
||||
[RegisterComponent, Access(typeof(CP14SalarySystem))]
|
||||
public sealed partial class CP14SalarySpawnerComponent : Component
|
||||
{
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
using System.Text;
|
||||
using Content.Server._CP14.Cargo;
|
||||
using Content.Server._CP14.Currency;
|
||||
using Content.Server.Station.Events;
|
||||
using Content.Shared.Paper;
|
||||
using Content.Shared.Station.Components;
|
||||
using Content.Shared.Storage.EntitySystems;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server._CP14.RoleSalary;
|
||||
|
||||
/// <summary>
|
||||
/// A system that periodically sends paychecks to certain roles through the cargo ship system
|
||||
/// </summary>
|
||||
public sealed partial class CP14SalarySystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly CP14CargoSystem _cargo = default!;
|
||||
[Dependency] private readonly TransformSystem _transform = default!;
|
||||
[Dependency] private readonly PaperSystem _paper = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly CP14CurrencySystem _currency = default!;
|
||||
[Dependency] private readonly SharedStorageSystem _storage = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14StationSalaryComponent, StationPostInitEvent>(OnStationPostInit);
|
||||
SubscribeLocalEvent<CP14SalarySpawnerComponent, MapInitEvent>(OnSalaryInit);
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
//var query = EntityQueryEnumerator<CP14StationSalaryComponent, CP14StationTravelingStoreShipTargetComponent>();
|
||||
//while (query.MoveNext(out var uid, out var salary, out var store))
|
||||
//{
|
||||
// if (_timing.CurTime < salary.NextSalaryTime)
|
||||
// continue;
|
||||
//
|
||||
// salary.NextSalaryTime = _timing.CurTime + salary.SalaryFrequency;
|
||||
// _cargo.AddBuyQueue((uid, store), new List<EntProtoId> {salary.SalaryProto});
|
||||
//}
|
||||
}
|
||||
|
||||
private void OnSalaryInit(Entity<CP14SalarySpawnerComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
GenerateSalary(ent);
|
||||
QueueDel(ent);
|
||||
}
|
||||
|
||||
private void GenerateSalary(Entity<CP14SalarySpawnerComponent> ent)
|
||||
{
|
||||
//Hardcode warning! ^-^
|
||||
var xform = Transform(ent);
|
||||
|
||||
//First we need found a station
|
||||
if (!TryComp<StationMemberComponent>(xform.GridUid, out var member))
|
||||
return;
|
||||
|
||||
if (!TryComp<CP14StationSalaryComponent>(member.Station, out var stationSalaryComponent))
|
||||
return;
|
||||
|
||||
var paper = Spawn("CP14Paper"); //TODO Special named paper
|
||||
_transform.PlaceNextTo(paper, (ent, xform));
|
||||
if (TryComp<PaperComponent>(paper, out var paperComp))
|
||||
{
|
||||
paperComp.Content = GenerateSalaryText((member.Station, stationSalaryComponent)) ?? "";
|
||||
_paper.TryStamp((paper, paperComp),
|
||||
new StampDisplayInfo
|
||||
{
|
||||
StampedColor = Color.Red,
|
||||
StampedName = Loc.GetString("cp14-stamp-salary"),
|
||||
},
|
||||
"red_on_paper");
|
||||
}
|
||||
|
||||
var wallet = Spawn("CP14Wallet");
|
||||
_transform.PlaceNextTo(wallet, (ent, xform));
|
||||
|
||||
foreach (var salary in stationSalaryComponent.Salary)
|
||||
{
|
||||
var coins = _currency.GenerateMoney(salary.Value, xform.Coordinates);
|
||||
foreach (var coin in coins)
|
||||
{
|
||||
_storage.Insert(wallet, coin, out _);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string? GenerateSalaryText(Entity<CP14StationSalaryComponent> station)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append(Loc.GetString("cp14-salary-title") + "\n");
|
||||
foreach (var salary in station.Comp.Salary)
|
||||
{
|
||||
sb.Append("\n");
|
||||
if (!_proto.TryIndex(salary.Key, out var indexedDep))
|
||||
continue;
|
||||
|
||||
var name = Loc.GetString(indexedDep.Name);
|
||||
sb.Append(Loc.GetString("cp14-salary-entry",
|
||||
("dep", name),
|
||||
("total", _currency.GetCurrencyPrettyString(salary.Value))));
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private void OnStationPostInit(Entity<CP14StationSalaryComponent> ent, ref StationPostInitEvent args)
|
||||
{
|
||||
ent.Comp.NextSalaryTime = _timing.CurTime + ent.Comp.SalaryFrequency;
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.RoleSalary;
|
||||
|
||||
[RegisterComponent, Access(typeof(CP14SalarySystem)), AutoGenerateComponentPause]
|
||||
public sealed partial class CP14StationSalaryComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// listing all the departments and their salaries
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public Dictionary<ProtoId<DepartmentPrototype>, int> Salary = new();
|
||||
|
||||
[DataField, AutoPausedField]
|
||||
public TimeSpan NextSalaryTime = TimeSpan.Zero;
|
||||
|
||||
[DataField]
|
||||
public TimeSpan SalaryFrequency = TimeSpan.FromMinutes(18);
|
||||
|
||||
[DataField]
|
||||
public EntProtoId SalaryProto = "CP14SalarySpawner";
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Shared.CCVar;
|
||||
using Robust.Server;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Console;
|
||||
|
||||
@@ -9,9 +10,10 @@ public sealed partial class CP14RoundEndSystem
|
||||
{
|
||||
[Dependency] private readonly IConsoleHost _consoleHost = default!;
|
||||
[Dependency] private readonly GameTicker _ticker = default!;
|
||||
[Dependency] private readonly IBaseServer _baseServer = default!;
|
||||
|
||||
private TimeSpan _nextUpdateTime = TimeSpan.Zero;
|
||||
private readonly TimeSpan _updateFrequency = TimeSpan.FromSeconds(60f);
|
||||
private readonly TimeSpan _updateFrequency = TimeSpan.FromSeconds(50f);
|
||||
|
||||
private bool _enabled;
|
||||
|
||||
@@ -24,7 +26,8 @@ public sealed partial class CP14RoundEndSystem
|
||||
}
|
||||
|
||||
// Вы можете сказать: Эд, ты ебанулся? Это же лютый щиткод!
|
||||
// И я вам отвечу: Да. Но сама система ограничения времени работы сервера - временная штука на этап разработки, которая будет удалена. Мне просто лень каждый раз запускать и выключать сервер ручками.
|
||||
// И я вам отвечу: Да. Но сама система ограничения времени работы сервера - временная штука на этап разработки, которая будет удалена.
|
||||
// Мне просто лень каждый раз запускать и выключать сервер ручками.
|
||||
private void UpdateCbt(float _)
|
||||
{
|
||||
if (!_enabled || _timing.CurTime < _nextUpdateTime)
|
||||
@@ -33,16 +36,16 @@ public sealed partial class CP14RoundEndSystem
|
||||
_nextUpdateTime = _timing.CurTime + _updateFrequency;
|
||||
var now = DateTime.UtcNow.AddHours(3); // Moscow time
|
||||
|
||||
OpenWeekendRule(now);
|
||||
EnglishDayRule(now);
|
||||
OpenSaturdayRule(now);
|
||||
LanguageRule(now);
|
||||
LimitPlaytimeRule(now);
|
||||
ApplyAnnouncements(now);
|
||||
}
|
||||
|
||||
private void OpenWeekendRule(DateTime now)
|
||||
private void OpenSaturdayRule(DateTime now)
|
||||
{
|
||||
var curWhitelist = _cfg.GetCVar(CCVars.WhitelistEnabled);
|
||||
var isOpenWeened = now.DayOfWeek is DayOfWeek.Saturday or DayOfWeek.Sunday;
|
||||
var isOpenWeened = now.DayOfWeek is DayOfWeek.Saturday;
|
||||
|
||||
if (isOpenWeened && curWhitelist)
|
||||
{
|
||||
@@ -54,22 +57,14 @@ public sealed partial class CP14RoundEndSystem
|
||||
}
|
||||
}
|
||||
|
||||
private void EnglishDayRule(DateTime now)
|
||||
private void LanguageRule(DateTime now)
|
||||
{
|
||||
var curLang = _cfg.GetCVar(CCVars.Language);
|
||||
var englishDay = now.DayOfWeek == DayOfWeek.Saturday;
|
||||
|
||||
if (englishDay && curLang != "en-US")
|
||||
{
|
||||
_cfg.SetCVar(CCVars.Language, "en-US");
|
||||
var ruHalfDay = now.Hour < 19 && now.Hour >= 9;
|
||||
|
||||
_chatSystem.DispatchGlobalAnnouncement(
|
||||
"WARNING: The server changes its language to English. For the changes to apply to your device, reconnect to the server.",
|
||||
announcementSound: new SoundPathSpecifier("/Audio/Effects/beep1.ogg"),
|
||||
sender: "Server"
|
||||
);
|
||||
}
|
||||
else if (!englishDay && curLang != "ru-RU")
|
||||
|
||||
if (ruHalfDay && curLang != "ru-RU")
|
||||
{
|
||||
_cfg.SetCVar(CCVars.Language, "ru-RU");
|
||||
|
||||
@@ -79,11 +74,21 @@ public sealed partial class CP14RoundEndSystem
|
||||
sender: "Server"
|
||||
);
|
||||
}
|
||||
else if (!ruHalfDay && curLang != "en-US")
|
||||
{
|
||||
_cfg.SetCVar(CCVars.Language, "en-US");
|
||||
|
||||
_chatSystem.DispatchGlobalAnnouncement(
|
||||
"WARNING: The server changes its language to English. For the changes to apply to your device, reconnect to the server.",
|
||||
announcementSound: new SoundPathSpecifier("/Audio/Effects/beep1.ogg"),
|
||||
sender: "Server"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void LimitPlaytimeRule(DateTime now)
|
||||
{
|
||||
var playtime = now.Hour is >= 18 and < 21;
|
||||
var playtime = (now.Hour is >= 15 and < 19) || (now.Hour is >= 20 and < 24);
|
||||
|
||||
if (playtime)
|
||||
{
|
||||
@@ -104,7 +109,7 @@ public sealed partial class CP14RoundEndSystem
|
||||
{
|
||||
var timeMap = new (int Hour, int Minute, Action Action)[]
|
||||
{
|
||||
(20, 45, () =>
|
||||
(18, 45, () =>
|
||||
{
|
||||
_chatSystem.DispatchGlobalAnnouncement(
|
||||
Loc.GetString("cp14-cbt-close-15m"),
|
||||
@@ -112,7 +117,19 @@ public sealed partial class CP14RoundEndSystem
|
||||
sender: "Server"
|
||||
);
|
||||
}),
|
||||
(21, 2, () =>
|
||||
(19, 2, () =>
|
||||
{
|
||||
_baseServer.Shutdown("Русский ОБТ подошел к концу. Следующие 3 часа будет английский ОБТ. Просьба не мешать англоязычным ребятам играть в свое время :)");
|
||||
}),
|
||||
(23, 45, () =>
|
||||
{
|
||||
_chatSystem.DispatchGlobalAnnouncement(
|
||||
Loc.GetString("cp14-cbt-close-15m"),
|
||||
announcementSound: new SoundPathSpecifier("/Audio/Effects/beep1.ogg"),
|
||||
sender: "Server"
|
||||
);
|
||||
}),
|
||||
(00, 2, () =>
|
||||
{
|
||||
_consoleHost.ExecuteCommand("golobby");
|
||||
}),
|
||||
|
||||
@@ -51,7 +51,7 @@ public sealed partial class CP14RoundEndSystem : EntitySystem
|
||||
|
||||
_demiplane.DeleteAllDemiplanes(safe: false);
|
||||
_chatSystem.DispatchGlobalAnnouncement(Loc.GetString("cp14-round-end"),
|
||||
announcementSound: new SoundPathSpecifier("/Audio/_CP14/Ambience/event_boom.ogg"));
|
||||
announcementSound: new SoundPathSpecifier("/Audio/_CP14/Announce/event_boom.ogg"));
|
||||
_roundEnd.EndRound();
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ public sealed partial class CP14RoundEndSystem : EntitySystem
|
||||
{
|
||||
_chatSystem.DispatchGlobalAnnouncement(
|
||||
Loc.GetString("cp14-round-end-monolith-50"),
|
||||
announcementSound: new SoundPathSpecifier("/Audio/_CP14/Ambience/event_boom.ogg"));
|
||||
announcementSound: new SoundPathSpecifier("/Audio/_CP14/Announce/event_boom.ogg"));
|
||||
}
|
||||
|
||||
//We initiate round end timer
|
||||
@@ -99,7 +99,7 @@ public sealed partial class CP14RoundEndSystem : EntitySystem
|
||||
"cp14-round-end-monolith-discharged",
|
||||
("time", time),
|
||||
("units", Loc.GetString(unitsLocString))),
|
||||
announcementSound: new SoundPathSpecifier("/Audio/_CP14/Ambience/event_boom.ogg"));
|
||||
announcementSound: new SoundPathSpecifier("/Audio/_CP14/Announce/event_boom.ogg"));
|
||||
}
|
||||
|
||||
private void CancelRoundEndTimer()
|
||||
@@ -107,6 +107,6 @@ public sealed partial class CP14RoundEndSystem : EntitySystem
|
||||
_roundEndMoment = TimeSpan.Zero;
|
||||
|
||||
_chatSystem.DispatchGlobalAnnouncement(Loc.GetString("cp14-round-end-monolith-recharged"),
|
||||
announcementSound: new SoundPathSpecifier("/Audio/_CP14/Ambience/event_boom.ogg"));
|
||||
announcementSound: new SoundPathSpecifier("/Audio/_CP14/Announce/event_boom.ogg"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ public sealed class CP14RoundLeaveSystem : EntitySystem
|
||||
|
||||
_adminLog.Add(LogType.Action,
|
||||
LogImpact.High,
|
||||
$"{ToPrettyString(ent):player} was leave the round by ghosting into mist");
|
||||
$"{ToPrettyString(ent):player} left the round by ghosting into mist");
|
||||
|
||||
LeaveRound(ent, userId.Value, args.Mind);
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
namespace Content.Server._CP14.RoundRemoveShuttle;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14RoundRemoveShuttleComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public EntityUid Station;
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Server.Mind;
|
||||
using Content.Server.Shuttles.Events;
|
||||
using Content.Server.Station.Systems;
|
||||
using Content.Server.StationRecords;
|
||||
using Content.Server.StationRecords.Systems;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Content.Shared.StationRecords;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.RoundRemoveShuttle;
|
||||
|
||||
public sealed partial class CP14RoundRemoveShuttleSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLog = default!;
|
||||
[Dependency] private readonly ChatSystem _chatSystem = default!;
|
||||
[Dependency] private readonly MindSystem _mind = default!;
|
||||
[Dependency] private readonly StationJobsSystem _stationJobs = default!;
|
||||
[Dependency] private readonly MobStateSystem _mobState = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly StationRecordsSystem _stationRecords = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
|
||||
private readonly HashSet<Entity<MindContainerComponent>> _mindSet = new();
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14RoundRemoveShuttleComponent, FTLStartedEvent>(OnFTL);
|
||||
}
|
||||
|
||||
private void OnFTL(Entity<CP14RoundRemoveShuttleComponent> ent, ref FTLStartedEvent args)
|
||||
{
|
||||
_mindSet.Clear();
|
||||
_lookup.GetChildEntities(ent, _mindSet);
|
||||
|
||||
if (!TryComp<StationRecordsComponent>(ent.Comp.Station, out var stationRecords))
|
||||
return;
|
||||
|
||||
HashSet<EntityUid> toDelete = new();
|
||||
var query = EntityQueryEnumerator<MindContainerComponent>();
|
||||
while (query.MoveNext(out var uid, out var mindContainer))
|
||||
{
|
||||
if (Transform(uid).GridUid != ent)
|
||||
continue;
|
||||
|
||||
if (!_mind.TryGetMind(uid, out _, out var mindComp, container: mindContainer))
|
||||
continue;
|
||||
|
||||
var name = Name(uid);
|
||||
var recordId = _stationRecords.GetRecordByName(ent.Comp.Station, name);
|
||||
|
||||
if (recordId is null)
|
||||
return;
|
||||
|
||||
var key = new StationRecordKey(recordId.Value, ent.Comp.Station);
|
||||
if (!_stationRecords.TryGetRecord<GeneralStationRecord>(key, out var entry, stationRecords))
|
||||
return;
|
||||
|
||||
_stationRecords.RemoveRecord(key, stationRecords);
|
||||
//Trying return all jobs roles
|
||||
var userId = mindComp.UserId;
|
||||
string? jobName = entry.JobTitle;
|
||||
if (userId is not null)
|
||||
{
|
||||
_stationJobs.TryAdjustJobSlot(ent.Comp.Station, entry.JobPrototype, 1, clamp: true);
|
||||
if (_proto.TryIndex(entry.JobPrototype, out var indexedJob))
|
||||
{
|
||||
jobName = Loc.GetString(indexedJob.Name);
|
||||
}
|
||||
}
|
||||
|
||||
_adminLog.Add(LogType.Action,
|
||||
LogImpact.High,
|
||||
$"{ToPrettyString(uid):player} was leave the round on traveling merchant ship");
|
||||
|
||||
_chatSystem.DispatchStationAnnouncement(ent.Comp.Station,
|
||||
Loc.GetString(
|
||||
_mobState.IsDead(uid) ? "cp14-earlyleave-ship-announcement-dead" : "cp14-earlyleave-ship-announcement",
|
||||
("character", mindComp.CharacterName ?? "Unknown"),
|
||||
("job", CultureInfo.CurrentCulture.TextInfo.ToTitleCase(jobName ?? "Unknown"))
|
||||
),
|
||||
Loc.GetString("cp14-ship-sender"),
|
||||
playDefaultSound: false
|
||||
);
|
||||
toDelete.Add(uid);
|
||||
}
|
||||
|
||||
while (toDelete.Count > 0)
|
||||
{
|
||||
var r = toDelete.First();
|
||||
toDelete.Remove(r);
|
||||
QueueDel(r);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
using System.Text;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Shared._CP14.RoundStatistic;
|
||||
using Content.Shared.GameTicking;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.RoundStatistic;
|
||||
|
||||
public sealed partial class CP14RoundStatTrackerSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
|
||||
private readonly Dictionary<ProtoId<CP14RoundStatTrackerPrototype>, int> _tracking = new();
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
InitializeDemiplaneDeath();
|
||||
|
||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundReset);
|
||||
SubscribeLocalEvent<RoundEndTextAppendEvent>(OnRoundEndTextAppend);
|
||||
ClearStatistic();
|
||||
}
|
||||
|
||||
private void OnRoundReset(RoundRestartCleanupEvent ev)
|
||||
{
|
||||
ClearStatistic();
|
||||
}
|
||||
|
||||
private void OnRoundEndTextAppend(RoundEndTextAppendEvent ev)
|
||||
{
|
||||
//TODO: Move to separate UI Text block
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.Append($"[head=3]{Loc.GetString("cp14-tracker-header")}[/head] \n");
|
||||
foreach (var pair in _tracking)
|
||||
{
|
||||
if (!_proto.TryIndex(pair.Key, out var indexedTracker))
|
||||
continue;
|
||||
|
||||
sb.Append($"- {Loc.GetString(indexedTracker.Text)}: {pair.Value}\n");
|
||||
}
|
||||
ev.AddLine(sb.ToString());
|
||||
}
|
||||
|
||||
private void ClearStatistic()
|
||||
{
|
||||
_tracking.Clear();
|
||||
|
||||
foreach (var statTracker in _proto.EnumeratePrototypes<CP14RoundStatTrackerPrototype>())
|
||||
{
|
||||
_tracking.Add(statTracker.ID, 0);
|
||||
}
|
||||
}
|
||||
|
||||
public void TrackAdd(ProtoId<CP14RoundStatTrackerPrototype> proto, int dif)
|
||||
{
|
||||
_tracking[proto] += Math.Max(dif, 0);
|
||||
}
|
||||
|
||||
public int? GetTrack(ProtoId<CP14RoundStatTrackerPrototype> proto)
|
||||
{
|
||||
if (!_tracking.TryGetValue(proto, out var stat))
|
||||
{
|
||||
Log.Error($"Failed to get round statistic: {proto}");
|
||||
return null;
|
||||
}
|
||||
|
||||
return stat;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
using Content.Shared._CP14.RoundStatistic;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.RoundStatistic.DemiplaneDeath;
|
||||
|
||||
/// <summary>
|
||||
/// Tracks the destruction or full-blown death of this entity.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14DeathDemiplaneStatisticComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public ProtoId<CP14RoundStatTrackerPrototype> Statistic = "DemiplaneDeaths";
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
using Content.Server._CP14.Demiplane;
|
||||
using Content.Server._CP14.RoundStatistic.DemiplaneDeath;
|
||||
using Content.Shared._CP14.Demiplane.Components;
|
||||
using Content.Shared.GameTicking;
|
||||
|
||||
namespace Content.Server._CP14.RoundStatistic;
|
||||
|
||||
public sealed partial class CP14RoundStatTrackerSystem
|
||||
{
|
||||
private void InitializeDemiplaneDeath()
|
||||
{
|
||||
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(OnSpawnComplete);
|
||||
SubscribeLocalEvent<CP14DeathDemiplaneStatisticComponent, EntityTerminatingEvent>(OnEntityTerminated);
|
||||
SubscribeLocalEvent<CP14DeathDemiplaneStatisticComponent, CP14DemiplaneUnsafeExit>(OnDemiplaneUnsafeExit);
|
||||
}
|
||||
|
||||
private void OnSpawnComplete(PlayerSpawnCompleteEvent ev)
|
||||
{
|
||||
EnsureComp<CP14DeathDemiplaneStatisticComponent>(ev.Mob);
|
||||
}
|
||||
|
||||
private void OnDemiplaneUnsafeExit(Entity<CP14DeathDemiplaneStatisticComponent> ent, ref CP14DemiplaneUnsafeExit args)
|
||||
{
|
||||
TrackAdd(ent.Comp.Statistic, 1);
|
||||
}
|
||||
|
||||
//For round remove variants, like gibs or chasm falls
|
||||
private void OnEntityTerminated(Entity<CP14DeathDemiplaneStatisticComponent> ent, ref EntityTerminatingEvent args)
|
||||
{
|
||||
if (!HasComp<CP14DemiplaneComponent>(Transform(ent).MapUid))
|
||||
return;
|
||||
|
||||
TrackAdd(ent.Comp.Statistic, 1);
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.StealArea;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[RegisterComponent, AutoGenerateComponentPause]
|
||||
public sealed partial class CP14StealAreaAutoJobConnectComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public HashSet<ProtoId<JobPrototype>> Jobs = new();
|
||||
|
||||
[DataField]
|
||||
public HashSet<ProtoId<DepartmentPrototype>> Departments = new();
|
||||
|
||||
[DataField]
|
||||
public bool Stations = true;
|
||||
}
|
||||
@@ -1,104 +0,0 @@
|
||||
using Content.Server._CP14.StationCommonObjectives;
|
||||
using Content.Server.Mind;
|
||||
using Content.Server.Objectives.Components;
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Roles.Jobs;
|
||||
using Robust.Server.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.StealArea;
|
||||
|
||||
public sealed class CP14StealAreaAutoJobConnectSystem : EntitySystem
|
||||
{
|
||||
|
||||
[Dependency] private readonly MindSystem _mind = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
||||
[Dependency] private readonly SharedJobSystem _job = default!;
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14StealAreaAutoJobConnectComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<PlayerSpawnCompleteEvent>(OnPlayerSpawning);
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<CP14StealAreaAutoJobConnectComponent> autoConnect, ref MapInitEvent args)
|
||||
{
|
||||
if (!TryComp<StealAreaComponent>(autoConnect, out var stealArea))
|
||||
return;
|
||||
|
||||
if (autoConnect.Comp.Stations)
|
||||
{
|
||||
var query = EntityQueryEnumerator<CP14StationCommonObjectivesComponent>();
|
||||
while (query.MoveNext(out var uid, out _))
|
||||
{
|
||||
stealArea.Owners.Add(uid);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var player in _playerManager.Sessions)
|
||||
{
|
||||
if (!_mind.TryGetMind(player.UserId, out var playerMind))
|
||||
continue;
|
||||
|
||||
if (!_job.MindTryGetJob(playerMind, out var playerJob))
|
||||
continue;
|
||||
|
||||
if (stealArea.Owners.Contains(playerMind.Value))
|
||||
continue;
|
||||
|
||||
if (autoConnect.Comp.Jobs.Contains(playerJob))
|
||||
{
|
||||
stealArea.Owners.Add(playerMind.Value);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var depObj in autoConnect.Comp.Departments)
|
||||
{
|
||||
if (!_proto.TryIndex(depObj, out var indexedDepart))
|
||||
continue;
|
||||
|
||||
if (!indexedDepart.Roles.Contains(playerJob))
|
||||
continue;
|
||||
|
||||
stealArea.Owners.Add(playerMind.Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPlayerSpawning(PlayerSpawnCompleteEvent ev)
|
||||
{
|
||||
if (!_mind.TryGetMind(ev.Player.UserId, out var mind))
|
||||
return;
|
||||
|
||||
var query = EntityQueryEnumerator<StealAreaComponent, CP14StealAreaAutoJobConnectComponent>();
|
||||
while (query.MoveNext(out var uid, out var stealArea, out var autoConnect))
|
||||
{
|
||||
if (stealArea.Owners.Contains(mind.Value))
|
||||
continue;
|
||||
|
||||
if (ev.JobId is null)
|
||||
continue;
|
||||
|
||||
if (autoConnect.Jobs.Contains(ev.JobId))
|
||||
{
|
||||
stealArea.Owners.Add(mind.Value);
|
||||
break;
|
||||
}
|
||||
|
||||
foreach (var depObj in autoConnect.Departments)
|
||||
{
|
||||
if (!_proto.TryIndex(depObj, out var indexedDepart))
|
||||
continue;
|
||||
|
||||
if (!indexedDepart.Roles.Contains(ev.JobId))
|
||||
continue;
|
||||
|
||||
stealArea.Owners.Add(mind.Value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ public sealed partial class CP14WorkbenchComponent : Component
|
||||
public float CraftSpeed = 1f;
|
||||
|
||||
[DataField]
|
||||
public float WorkbenchRadius = 0.5f;
|
||||
public float WorkbenchRadius = 1.5f;
|
||||
|
||||
/// <summary>
|
||||
/// List of recipes available for crafting on this type of workbench
|
||||
|
||||
@@ -35,10 +35,11 @@ public sealed partial class CP14WorkbenchSystem
|
||||
|
||||
foreach (var requirement in indexedRecipe.Requirements)
|
||||
{
|
||||
if (!requirement.CheckRequirement(EntityManager, _proto, placedEntities, user, indexedRecipe))
|
||||
if (!requirement.CheckRequirement(EntityManager, _proto, placedEntities, user))
|
||||
{
|
||||
canCraft = false;
|
||||
hidden = requirement.HideRecipe;
|
||||
if (requirement.HideRecipe)
|
||||
hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._CP14.Workbench;
|
||||
|
||||
public sealed partial class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
|
||||
public sealed partial class CP14WorkbenchSystem : CP14SharedWorkbenchSystem
|
||||
{
|
||||
[Dependency] private readonly AudioSystem _audio = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
@@ -139,7 +139,7 @@ public sealed partial class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
|
||||
{
|
||||
foreach (var req in recipe.Requirements)
|
||||
{
|
||||
if (!req.CheckRequirement(EntityManager, _proto, entities, user, recipe))
|
||||
if (!req.CheckRequirement(EntityManager, _proto, entities, user))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared._CP14.DayCycle;
|
||||
using Content.Shared.Light.Components;
|
||||
using Robust.Shared.Map.Components;
|
||||
|
||||
@@ -14,6 +15,10 @@ public abstract class SharedLightCycleSystem : EntitySystem
|
||||
|
||||
protected virtual void OnCycleMapInit(Entity<LightCycleComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
//CP14DayCycleSystem
|
||||
EnsureComp<CP14DayCycleComponent>(ent);
|
||||
//CP14DayCycleSystem end
|
||||
|
||||
if (TryComp(ent.Owner, out MapLightComponent? mapLight))
|
||||
{
|
||||
ent.Comp.OriginalColor = mapLight.AmbientLightColor;
|
||||
|
||||
@@ -48,14 +48,8 @@ public sealed partial class LoadoutPrototype : IPrototype, IEquipmentLoadout
|
||||
public Dictionary<string, List<EntProtoId>> Storage { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// CP14 - it is possible to give action spells or spells to players who have taken this loadout
|
||||
/// CP14 - it is possible to give free skills to players
|
||||
/// </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();
|
||||
public HashSet<ProtoId<CP14SkillPrototype>> Skills = new();
|
||||
}
|
||||
|
||||
@@ -97,14 +97,9 @@ public abstract class SharedStationSpawningSystem : EntitySystem
|
||||
|
||||
private void CP14EquipStartingActions(EntityUid entity, LoadoutPrototype loadout)
|
||||
{
|
||||
foreach (var action in loadout.Actions)
|
||||
foreach (var skill in loadout.Skills)
|
||||
{
|
||||
_action.AddAction(entity, action);
|
||||
}
|
||||
|
||||
foreach (var tree in loadout.SkillTree)
|
||||
{
|
||||
_skill.TryAddExperience(entity, tree.Key, tree.Value);
|
||||
_skill.TryAddSkill(entity, skill, free: true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.BloodMoon;
|
||||
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class CP14BloodMoonCurseComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public EntityUid? CurseRule;
|
||||
|
||||
[DataField]
|
||||
public EntProtoId CurseEffect = "CP14BloodMoonCurseEffect";
|
||||
|
||||
[DataField]
|
||||
public EntityUid? SpawnedEffect;
|
||||
|
||||
[DataField]
|
||||
public TimeSpan EndStunDuration = TimeSpan.FromSeconds(60f);
|
||||
|
||||
[DataField]
|
||||
public EntProtoId Action = "CP14ActionSpellBloodlust";
|
||||
|
||||
[DataField]
|
||||
public EntityUid? ActionEntity;
|
||||
}
|
||||
11
Content.Shared/_CP14/DayCycle/CP14DayCycleComponent.cs
Normal file
11
Content.Shared/_CP14/DayCycle/CP14DayCycleComponent.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace Content.Shared._CP14.DayCycle;
|
||||
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14DayCycleComponent : Component
|
||||
{
|
||||
public float LastLightLevel = 0f;
|
||||
|
||||
[DataField]
|
||||
public float Threshold = 0.6f;
|
||||
}
|
||||
130
Content.Shared/_CP14/DayCycle/CP14DayCycleSystem.cs
Normal file
130
Content.Shared/_CP14/DayCycle/CP14DayCycleSystem.cs
Normal file
@@ -0,0 +1,130 @@
|
||||
using Content.Shared.GameTicking;
|
||||
using Content.Shared.Light.Components;
|
||||
using Content.Shared.Storage.Components;
|
||||
using Content.Shared.Weather;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Shared._CP14.DayCycle;
|
||||
|
||||
/// <summary>
|
||||
/// This is an add-on to the LightCycle system that helps you determine what time of day it is on the map
|
||||
/// </summary>
|
||||
public sealed class CP14DayCycleSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IGameTiming _timing = default!;
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly SharedGameTicker _ticker = default!;
|
||||
[Dependency] private readonly SharedMapSystem _maps = default!;
|
||||
[Dependency] private readonly SharedWeatherSystem _weather = default!;
|
||||
|
||||
private EntityQuery<MapGridComponent> _mapGridQuery;
|
||||
private EntityQuery<InsideEntityStorageComponent> _storageQuery;
|
||||
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_mapGridQuery = GetEntityQuery<MapGridComponent>();
|
||||
_storageQuery = GetEntityQuery<InsideEntityStorageComponent>();
|
||||
}
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<LightCycleComponent, CP14DayCycleComponent, MapComponent>();
|
||||
while (query.MoveNext(out var uid, out var lightCycle, out var dayCycle, out var map))
|
||||
{
|
||||
var oldLightLevel = dayCycle.LastLightLevel;
|
||||
var newLightLevel = GetLightLevel((uid, lightCycle));
|
||||
|
||||
// Going into darkness
|
||||
if (oldLightLevel > newLightLevel)
|
||||
{
|
||||
if (oldLightLevel > dayCycle.Threshold)
|
||||
{
|
||||
if (newLightLevel < dayCycle.Threshold)
|
||||
{
|
||||
var ev = new CP14StartNightEvent(uid);
|
||||
RaiseLocalEvent(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Going into light
|
||||
if (oldLightLevel < newLightLevel)
|
||||
{
|
||||
if (oldLightLevel < dayCycle.Threshold)
|
||||
{
|
||||
if (newLightLevel > dayCycle.Threshold)
|
||||
{
|
||||
var ev = new CP14StartDayEvent(uid);
|
||||
RaiseLocalEvent(ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dayCycle.LastLightLevel = newLightLevel;
|
||||
}
|
||||
}
|
||||
|
||||
public float GetLightLevel(Entity<LightCycleComponent?> map)
|
||||
{
|
||||
if (!Resolve(map.Owner, ref map.Comp, false))
|
||||
return 0;
|
||||
|
||||
var time = (float)_timing.CurTime
|
||||
.Add(map.Comp.Offset)
|
||||
.Subtract(_ticker.RoundStartTimeSpan)
|
||||
.Subtract(_metaData.GetPauseTime(map))
|
||||
.TotalSeconds;
|
||||
|
||||
var normalizedTime = time % map.Comp.Duration.TotalSeconds;
|
||||
var lightLevel = Math.Sin((normalizedTime / map.Comp.Duration.TotalSeconds) * MathF.PI);
|
||||
return (float)lightLevel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks to see if the specified entity is on the map where it's daytime.
|
||||
/// </summary>
|
||||
/// <param name="target">An entity being tested to see if it is in daylight</param>
|
||||
public bool UnderSunlight(EntityUid target)
|
||||
{
|
||||
if (_storageQuery.HasComp(target))
|
||||
return false;
|
||||
|
||||
var xform = Transform(target);
|
||||
|
||||
if (xform.MapUid is null || xform.GridUid is null)
|
||||
return false;
|
||||
|
||||
var day = GetLightLevel(xform.MapUid.Value) > 0.5f;
|
||||
|
||||
var grid = xform.GridUid;
|
||||
if (grid is null)
|
||||
return day;
|
||||
|
||||
if (!_mapGridQuery.TryComp(grid, out var gridComp))
|
||||
return day;
|
||||
|
||||
if (!_weather.CanWeatherAffect(grid.Value,
|
||||
gridComp,
|
||||
_maps.GetTileRef(xform.GridUid.Value, gridComp, xform.Coordinates)))
|
||||
return false;
|
||||
|
||||
return day;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CP14StartNightEvent(EntityUid map) : EntityEventArgs
|
||||
{
|
||||
public EntityUid Map = map;
|
||||
}
|
||||
|
||||
public sealed class CP14StartDayEvent(EntityUid map) : EntityEventArgs
|
||||
{
|
||||
public EntityUid Map = map;
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.Decals;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CP14DecalCleanerDoAfterEvent : DoAfterEvent
|
||||
{
|
||||
public NetCoordinates ClickLocation;
|
||||
|
||||
public CP14DecalCleanerDoAfterEvent(NetCoordinates click)
|
||||
{
|
||||
ClickLocation = click;
|
||||
}
|
||||
|
||||
public override DoAfterEvent Clone() => this;
|
||||
}
|
||||
@@ -29,5 +29,5 @@ public sealed partial class CP14SpecialDemiplanePrototype : IPrototype
|
||||
/// Modifiers that will be automatically added to the demiplane when it is generated.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<ProtoId<CP14DemiplaneModifierPrototype>>? Modifiers = new();
|
||||
public List<ProtoId<CP14DemiplaneModifierPrototype>> Modifiers = new();
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
namespace Content.Shared._CP14.MagicAttuning;
|
||||
|
||||
/// <summary>
|
||||
/// Reflects the fact that this subject can be focused on (Magical attune as a mechanic from DnD.)
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicAttuningSystem))]
|
||||
public sealed partial class CP14MagicAttuningItemComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// how long it takes to focus on that object
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public TimeSpan FocusTime = TimeSpan.FromSeconds(5f);
|
||||
|
||||
public Entity<CP14MagicAttuningMindComponent>? Link = null;
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._CP14.MagicAttuning;
|
||||
|
||||
/// <summary>
|
||||
/// A mind that can focus on objects
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
[Access(typeof(CP14SharedMagicAttuningSystem))]
|
||||
public sealed partial class CP14MagicAttuningMindComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public int MaxAttuning = 3;
|
||||
/// <summary>
|
||||
/// The entities that this being is focused on
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<EntityUid> AttunedTo = new();
|
||||
|
||||
/// <summary>
|
||||
/// cheat: if added to an entity with MindContainer, automatically copied to the mind, removing it from the body. This is to make it easy to add the component to prototype creatures.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool AutoCopyToMind = false;
|
||||
}
|
||||
@@ -1,238 +0,0 @@
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.MagicAttuning;
|
||||
|
||||
/// <summary>
|
||||
/// This system controls the customization to magic items by the players.
|
||||
/// </summary>
|
||||
public sealed partial class CP14SharedMagicAttuningSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14MagicAttuningItemComponent, GetVerbsEvent<InteractionVerb>>(OnInteractionVerb);
|
||||
SubscribeLocalEvent<CP14MagicAttuningMindComponent, CP14MagicAttuneDoAfterEvent>(OnAttuneDoAfter);
|
||||
SubscribeLocalEvent<CP14MagicAttuningMindComponent, MindAddedMessage>(OnMindAdded);
|
||||
}
|
||||
|
||||
private void OnMindAdded(Entity<CP14MagicAttuningMindComponent> ent, ref MindAddedMessage args)
|
||||
{
|
||||
if (!ent.Comp.AutoCopyToMind)
|
||||
return;
|
||||
|
||||
if (HasComp<MindComponent>(ent))
|
||||
return;
|
||||
|
||||
if (!_mind.TryGetMind(ent, out var mindId, out var mind))
|
||||
return;
|
||||
|
||||
if (!HasComp<CP14MagicAttuningMindComponent>(mindId))
|
||||
{
|
||||
var attuneMind = AddComp<CP14MagicAttuningMindComponent>(mindId);
|
||||
attuneMind.MaxAttuning = ent.Comp.MaxAttuning;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAttunedTo(EntityUid mind, EntityUid item)
|
||||
{
|
||||
if (!TryComp<CP14MagicAttuningItemComponent>(item, out var attuningItem))
|
||||
return false;
|
||||
|
||||
if (!TryComp<CP14MagicAttuningMindComponent>(mind, out var attuningMind))
|
||||
return false;
|
||||
|
||||
return attuningMind.AttunedTo.Contains(item);
|
||||
}
|
||||
|
||||
private void OnInteractionVerb(Entity<CP14MagicAttuningItemComponent> attuningItem, ref GetVerbsEvent<InteractionVerb> args)
|
||||
{
|
||||
if (!args.CanAccess || !args.CanInteract)
|
||||
return;
|
||||
|
||||
if (!_mind.TryGetMind(args.User, out var mindId, out var mind))
|
||||
return;
|
||||
|
||||
if (!TryComp<CP14MagicAttuningMindComponent>(mindId, out var attumingMind))
|
||||
return;
|
||||
|
||||
var user = args.User;
|
||||
if (attumingMind.AttunedTo.Contains(args.Target))
|
||||
{
|
||||
args.Verbs.Add(new()
|
||||
{
|
||||
Act = () =>
|
||||
{
|
||||
RemoveAttune((mindId, attumingMind), attuningItem);
|
||||
},
|
||||
Text = Loc.GetString("cp14-magic-deattuning-verb-text"),
|
||||
Message = Loc.GetString("cp14-magic-attuning-verb-message"),
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
args.Verbs.Add(new()
|
||||
{
|
||||
Act = () =>
|
||||
{
|
||||
TryStartAttune(user, attuningItem);
|
||||
},
|
||||
Text = Loc.GetString("cp14-magic-attuning-verb-text"),
|
||||
Message = Loc.GetString("cp14-magic-attuning-verb-message"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryStartAttune(EntityUid user, Entity<CP14MagicAttuningItemComponent> item)
|
||||
{
|
||||
if (!_mind.TryGetMind(user, out var mindId, out var mind))
|
||||
return false;
|
||||
|
||||
if (!TryComp<CP14MagicAttuningMindComponent>(mindId, out var attuningMind))
|
||||
return false;
|
||||
|
||||
if (attuningMind.MaxAttuning <= 0)
|
||||
return false;
|
||||
|
||||
//if there's an overabundance of ties, we report that the oldest one is torn.
|
||||
if (attuningMind.AttunedTo.Count >= attuningMind.MaxAttuning)
|
||||
{
|
||||
var oldestAttune = attuningMind.AttunedTo[0];
|
||||
_popup.PopupEntity(Loc.GetString("cp14-magic-attune-oldest-forgot", ("item", MetaData(oldestAttune).EntityName)), user, user);
|
||||
}
|
||||
|
||||
//we notify the current owner of the item that someone is cutting ties.
|
||||
if (item.Comp.Link is not null &&
|
||||
item.Comp.Link.Value.Owner != mindId &&
|
||||
TryComp<MindComponent>(item.Comp.Link.Value.Owner, out var ownerMind) &&
|
||||
ownerMind.OwnedEntity is not null)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cp14-magic-attune-oldest-forgot", ("item", MetaData(item).EntityName)), ownerMind.OwnedEntity.Value, ownerMind.OwnedEntity.Value);
|
||||
}
|
||||
|
||||
var doAfterArgs = new DoAfterArgs(EntityManager,
|
||||
user,
|
||||
item.Comp.FocusTime,
|
||||
new CP14MagicAttuneDoAfterEvent(),
|
||||
mindId,
|
||||
item)
|
||||
{
|
||||
BreakOnDamage = true,
|
||||
BreakOnMove = true,
|
||||
DistanceThreshold = 2f,
|
||||
BlockDuplicate = true,
|
||||
};
|
||||
|
||||
_doAfter.TryStartDoAfter(doAfterArgs);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnAttuneDoAfter(Entity<CP14MagicAttuningMindComponent> ent, ref CP14MagicAttuneDoAfterEvent args)
|
||||
{
|
||||
if (args.Cancelled || args.Handled || args.Target is null)
|
||||
return;
|
||||
|
||||
if (ent.Comp.AttunedTo.Count >= ent.Comp.MaxAttuning)
|
||||
{
|
||||
var oldestAttune = ent.Comp.AttunedTo[0];
|
||||
RemoveAttune(ent, oldestAttune);
|
||||
}
|
||||
|
||||
AddAttune(ent, args.Target.Value);
|
||||
}
|
||||
|
||||
private void RemoveAttune(Entity<CP14MagicAttuningMindComponent> attuningMind, EntityUid item)
|
||||
{
|
||||
if (!attuningMind.Comp.AttunedTo.Contains(item))
|
||||
return;
|
||||
|
||||
attuningMind.Comp.AttunedTo.Remove(item);
|
||||
|
||||
if (!TryComp<CP14MagicAttuningItemComponent>(item, out var attuningItem))
|
||||
return;
|
||||
|
||||
if (!TryComp<MindComponent>(attuningMind, out var mind))
|
||||
return;
|
||||
|
||||
attuningItem.Link = null;
|
||||
|
||||
var ev = new RemovedAttuneFromMindEvent(attuningMind, mind.OwnedEntity, item);
|
||||
RaiseLocalEvent(attuningMind, ev);
|
||||
RaiseLocalEvent(item, ev);
|
||||
|
||||
if (mind.OwnedEntity is not null)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cp14-magic-attune-oldest-forgot-end", ("item", MetaData(item).EntityName)), mind.OwnedEntity.Value, mind.OwnedEntity.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void AddAttune(Entity<CP14MagicAttuningMindComponent> attuningMind, EntityUid item)
|
||||
{
|
||||
if (attuningMind.Comp.AttunedTo.Contains(item))
|
||||
return;
|
||||
|
||||
if (!TryComp<CP14MagicAttuningItemComponent>(item, out var attuningItem))
|
||||
return;
|
||||
|
||||
if (!TryComp<MindComponent>(attuningMind, out var mind))
|
||||
return;
|
||||
|
||||
if (attuningItem.Link is not null)
|
||||
RemoveAttune(attuningItem.Link.Value, item);
|
||||
|
||||
attuningMind.Comp.AttunedTo.Add(item);
|
||||
attuningItem.Link = attuningMind;
|
||||
|
||||
|
||||
var ev = new AddedAttuneToMindEvent(attuningMind, mind.OwnedEntity, item);
|
||||
RaiseLocalEvent(attuningMind, ev);
|
||||
RaiseLocalEvent(item, ev);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CP14MagicAttuneDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// is evoked on both the item and the mind when a new connection between them appears.
|
||||
/// </summary>
|
||||
public sealed class AddedAttuneToMindEvent : EntityEventArgs
|
||||
{
|
||||
public readonly EntityUid Mind;
|
||||
public readonly EntityUid? User;
|
||||
public readonly EntityUid Item;
|
||||
|
||||
public AddedAttuneToMindEvent(EntityUid mind, EntityUid? user, EntityUid item)
|
||||
{
|
||||
Mind = mind;
|
||||
User = user;
|
||||
Item = item;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// is evoked on both the item and the mind when the connection is broken
|
||||
/// </summary>
|
||||
public sealed class RemovedAttuneFromMindEvent : EntityEventArgs
|
||||
{
|
||||
public readonly EntityUid Mind;
|
||||
public readonly EntityUid? User;
|
||||
public readonly EntityUid Item;
|
||||
|
||||
public RemovedAttuneFromMindEvent(EntityUid mind, EntityUid? user, EntityUid item)
|
||||
{
|
||||
Mind = mind;
|
||||
User = user;
|
||||
Item = item;
|
||||
}
|
||||
}
|
||||
@@ -58,6 +58,19 @@ public abstract class SharedCP14MagicEnergySystem : EntitySystem
|
||||
_ambient.SetAmbience(ent, args.Powered);
|
||||
}
|
||||
|
||||
private void UpdateMagicAlert(Entity<CP14MagicEnergyContainerComponent> ent)
|
||||
{
|
||||
if (ent.Comp.MagicAlert is null)
|
||||
return;
|
||||
|
||||
var level = ContentHelpers.RoundToLevels(
|
||||
MathF.Max(0f, (float) ent.Comp.Energy),
|
||||
(float) ent.Comp.MaxEnergy,
|
||||
_alerts.GetMaxSeverity(ent.Comp.MagicAlert.Value));
|
||||
|
||||
_alerts.ShowAlert(ent, ent.Comp.MagicAlert.Value, (short) level);
|
||||
}
|
||||
|
||||
public void ChangeEnergy(Entity<CP14MagicEnergyContainerComponent?> ent,
|
||||
FixedPoint2 energy,
|
||||
out FixedPoint2 deltaEnergy,
|
||||
@@ -154,17 +167,14 @@ public abstract class SharedCP14MagicEnergySystem : EntitySystem
|
||||
("color", color));
|
||||
}
|
||||
|
||||
private void UpdateMagicAlert(Entity<CP14MagicEnergyContainerComponent> ent)
|
||||
public void ChangeMaximumEnergy(Entity<CP14MagicEnergyContainerComponent?> ent, FixedPoint2 energy)
|
||||
{
|
||||
if (ent.Comp.MagicAlert is null)
|
||||
if (!Resolve(ent, ref ent.Comp, false))
|
||||
return;
|
||||
|
||||
var level = ContentHelpers.RoundToLevels(
|
||||
MathF.Max(0f, (float) ent.Comp.Energy),
|
||||
(float) ent.Comp.MaxEnergy,
|
||||
_alerts.GetMaxSeverity(ent.Comp.MagicAlert.Value));
|
||||
ent.Comp.MaxEnergy += energy;
|
||||
|
||||
_alerts.ShowAlert(ent, ent.Comp.MagicAlert.Value, (short) level);
|
||||
ChangeEnergy(ent, energy, out _, out _);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,4 +15,7 @@ public sealed partial class CP14MagicManacostModifyComponent : Component
|
||||
|
||||
[DataField]
|
||||
public FixedPoint2 GlobalModifier = 1f;
|
||||
|
||||
[DataField]
|
||||
public bool Examinable = false;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using Content.Shared._CP14.MagicRitual.Prototypes;
|
||||
using Content.Shared._CP14.MagicSpell.Events;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -24,10 +25,10 @@ public sealed partial class CP14MagicManacostModifySystem : EntitySystem
|
||||
|
||||
private void OnVerbExamine(Entity<CP14MagicManacostModifyComponent> ent, ref GetVerbsEvent<ExamineVerb> args)
|
||||
{
|
||||
if (!args.CanInteract || !args.CanAccess)
|
||||
if (!args.CanInteract || !args.CanAccess || !ent.Comp.Examinable)
|
||||
return;
|
||||
|
||||
var markup = GetMagicClothingExamine(ent.Comp);
|
||||
var markup = GetManacostModifyMessage(ent.Comp.GlobalModifier, ent.Comp.Modifiers);
|
||||
_examine.AddDetailedExamineVerb(
|
||||
args,
|
||||
ent.Comp,
|
||||
@@ -37,21 +38,21 @@ public sealed partial class CP14MagicManacostModifySystem : EntitySystem
|
||||
Loc.GetString("cp14-magic-examinable-verb-message"));
|
||||
}
|
||||
|
||||
private FormattedMessage GetMagicClothingExamine(CP14MagicManacostModifyComponent comp)
|
||||
public FormattedMessage GetManacostModifyMessage(FixedPoint2 global, Dictionary<ProtoId<CP14MagicTypePrototype>, FixedPoint2> modifiers)
|
||||
{
|
||||
var msg = new FormattedMessage();
|
||||
msg.AddMarkupOrThrow(Loc.GetString("cp14-clothing-magic-examine"));
|
||||
|
||||
if (comp.GlobalModifier != 1)
|
||||
if (global != 1)
|
||||
{
|
||||
msg.PushNewline();
|
||||
|
||||
var plus = (float)comp.GlobalModifier > 1 ? "+" : "";
|
||||
var plus = (float)global > 1 ? "+" : "";
|
||||
msg.AddMarkupOrThrow(
|
||||
$"{Loc.GetString("cp14-clothing-magic-global")}: {plus}{MathF.Round((float)(comp.GlobalModifier - 1) * 100, MidpointRounding.AwayFromZero)}%");
|
||||
$"{Loc.GetString("cp14-clothing-magic-global")}: {plus}{MathF.Round((float)(global - 1) * 100, MidpointRounding.AwayFromZero)}%");
|
||||
}
|
||||
|
||||
foreach (var modifier in comp.Modifiers)
|
||||
foreach (var modifier in modifiers)
|
||||
{
|
||||
if (modifier.Value == 1)
|
||||
continue;
|
||||
|
||||
52
Content.Shared/_CP14/MagicSpell/Spells/CP14SpellPointer.cs
Normal file
52
Content.Shared/_CP14/MagicSpell/Spells/CP14SpellPointer.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Spells;
|
||||
|
||||
public sealed partial class CP14SpellPointer : CP14SpellEffect
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public EntProtoId PointerEntity;
|
||||
|
||||
[DataField(required: true)]
|
||||
public EntityWhitelist? Whitelist;
|
||||
|
||||
[DataField]
|
||||
public EntityWhitelist? Blacklist = null;
|
||||
|
||||
[DataField(required: true)]
|
||||
public float SearchRange = 30f;
|
||||
|
||||
public override void Effect(EntityManager entManager, CP14SpellEffectBaseArgs args)
|
||||
{
|
||||
if (args.User is null)
|
||||
return;
|
||||
|
||||
var lookup = entManager.System<EntityLookupSystem>();
|
||||
var whitelistSys = entManager.System<EntityWhitelistSystem>();
|
||||
var transform = entManager.System<SharedTransformSystem>();
|
||||
|
||||
var originPosition = transform.GetWorldPosition(args.User.Value);
|
||||
var originEntPosition = transform.GetMoverCoordinates(args.User.Value);
|
||||
|
||||
var entitiesInRange = lookup.GetEntitiesInRange<TransformComponent>(originEntPosition, SearchRange);
|
||||
foreach (var ent in entitiesInRange)
|
||||
{
|
||||
if (ent.Owner == args.User.Value)
|
||||
continue;
|
||||
|
||||
if (!whitelistSys.CheckBoth(ent, Blacklist, Whitelist))
|
||||
continue;
|
||||
|
||||
var targetPosition = transform.GetWorldPosition(ent.Comp);
|
||||
|
||||
//Calculate the rotation
|
||||
Angle angle = new(targetPosition - originPosition);
|
||||
|
||||
var pointer = entManager.Spawn(PointerEntity, new MapCoordinates(originPosition, transform.GetMapId(originEntPosition)));
|
||||
|
||||
transform.SetWorldRotation(pointer, angle + Angle.FromDegrees(90));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
using Content.Shared.Mobs.Components;
|
||||
using Content.Shared.Mobs.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Spells;
|
||||
|
||||
public sealed partial class CP14SpellPointerToAlive : CP14SpellEffect
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public EntProtoId PointerEntity;
|
||||
|
||||
[DataField(required: true)]
|
||||
public float SearchRange = 30f;
|
||||
|
||||
public override void Effect(EntityManager entManager, CP14SpellEffectBaseArgs args)
|
||||
{
|
||||
if (args.User is null)
|
||||
return;
|
||||
|
||||
var lookup = entManager.System<EntityLookupSystem>();
|
||||
var mobStateSys = entManager.System<MobStateSystem>();
|
||||
var transform = entManager.System<SharedTransformSystem>();
|
||||
|
||||
var originPosition = transform.GetWorldPosition(args.User.Value);
|
||||
var originEntPosition = transform.GetMoverCoordinates(args.User.Value);
|
||||
|
||||
var entitiesInRange = lookup.GetEntitiesInRange<MobStateComponent>(originEntPosition, SearchRange);
|
||||
foreach (var ent in entitiesInRange)
|
||||
{
|
||||
if (ent.Owner == args.User.Value)
|
||||
continue;
|
||||
|
||||
if (mobStateSys.IsDead(ent))
|
||||
continue;
|
||||
|
||||
var targetPosition = transform.GetWorldPosition(ent);
|
||||
|
||||
//Calculate the rotation
|
||||
Angle angle = new(targetPosition - originPosition);
|
||||
|
||||
var pointer = entManager.Spawn(PointerEntity, new MapCoordinates(originPosition, transform.GetMapId(originEntPosition)));
|
||||
|
||||
transform.SetWorldRotation(pointer, angle + Angle.FromDegrees(90));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
using Content.Shared._CP14.MagicAttuning;
|
||||
using Content.Shared._CP14.MagicSpellStorage.Components;
|
||||
using Content.Shared.Clothing;
|
||||
using Content.Shared.Clothing.Components;
|
||||
using Content.Shared.Hands;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpellStorage;
|
||||
@@ -11,9 +9,7 @@ public sealed partial class CP14SpellStorageSystem
|
||||
private void InitializeAccess()
|
||||
{
|
||||
SubscribeLocalEvent<CP14SpellStorageAccessHoldingComponent, GotEquippedHandEvent>(OnEquippedHand);
|
||||
SubscribeLocalEvent<CP14SpellStorageAccessHoldingComponent, AddedAttuneToMindEvent>(OnHandAddedAttune);
|
||||
|
||||
SubscribeLocalEvent<CP14SpellStorageAccessWearingComponent, AddedAttuneToMindEvent>(OnClothingAddedAttune);
|
||||
SubscribeLocalEvent<CP14SpellStorageAccessWearingComponent, ClothingGotEquippedEvent>(OnClothingEquipped);
|
||||
SubscribeLocalEvent<CP14SpellStorageAccessWearingComponent, ClothingGotUnequippedEvent>(OnClothingUnequipped);
|
||||
}
|
||||
@@ -26,40 +22,6 @@ public sealed partial class CP14SpellStorageSystem
|
||||
TryGrantAccess((ent, spellStorage), args.User);
|
||||
}
|
||||
|
||||
private void OnHandAddedAttune(Entity<CP14SpellStorageAccessHoldingComponent> ent, ref AddedAttuneToMindEvent args)
|
||||
{
|
||||
if (!TryComp<CP14SpellStorageComponent>(ent, out var spellStorage))
|
||||
return;
|
||||
|
||||
if (args.User is null)
|
||||
return;
|
||||
|
||||
if (!_hands.IsHolding(args.User.Value, ent))
|
||||
return;
|
||||
|
||||
TryGrantAccess((ent, spellStorage), args.User.Value);
|
||||
}
|
||||
|
||||
private void OnClothingAddedAttune(Entity<CP14SpellStorageAccessWearingComponent> ent, ref AddedAttuneToMindEvent args)
|
||||
{
|
||||
if (!ent.Comp.Wearing)
|
||||
return;
|
||||
|
||||
if (!TryComp<CP14SpellStorageComponent>(ent, out var spellStorage))
|
||||
return;
|
||||
|
||||
if (args.User is null)
|
||||
return;
|
||||
|
||||
if (!TryComp<ClothingComponent>(ent, out var clothing))
|
||||
return;
|
||||
|
||||
if (Transform(ent).ParentUid != args.User)
|
||||
return;
|
||||
|
||||
TryGrantAccess((ent, spellStorage), args.User.Value);
|
||||
}
|
||||
|
||||
private void OnClothingEquipped(Entity<CP14SpellStorageAccessWearingComponent> ent, ref ClothingGotEquippedEvent args)
|
||||
{
|
||||
ent.Comp.Wearing = true;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
using Content.Shared._CP14.MagicAttuning;
|
||||
using Content.Shared._CP14.MagicSpell.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Events;
|
||||
using Content.Shared._CP14.MagicSpellStorage.Components;
|
||||
@@ -18,7 +17,6 @@ public sealed partial class CP14SpellStorageSystem : EntitySystem
|
||||
[Dependency] private readonly ActionContainerSystem _actionContainer = default!;
|
||||
[Dependency] private readonly SharedActionsSystem _actions = default!;
|
||||
[Dependency] private readonly SharedMindSystem _mind = default!;
|
||||
[Dependency] private readonly CP14SharedMagicAttuningSystem _attuning = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||
@@ -31,7 +29,6 @@ public sealed partial class CP14SpellStorageSystem : EntitySystem
|
||||
SubscribeLocalEvent<CP14SpellStorageComponent, ComponentShutdown>(OnMagicStorageShutdown);
|
||||
|
||||
SubscribeLocalEvent<CP14SpellStorageUseDamageComponent, CP14SpellFromSpellStorageUsedEvent>(OnSpellUsed);
|
||||
SubscribeLocalEvent<CP14SpellStorageRequireAttuneComponent, RemovedAttuneFromMindEvent>(OnRemovedAttune);
|
||||
}
|
||||
|
||||
private void OnSpellUsed(Entity<CP14SpellStorageUseDamageComponent> ent, ref CP14SpellFromSpellStorageUsedEvent args)
|
||||
@@ -81,21 +78,7 @@ public sealed partial class CP14SpellStorageSystem : EntitySystem
|
||||
if (mind.OwnedEntity is null)
|
||||
return false;
|
||||
|
||||
if (TryComp<CP14SpellStorageRequireAttuneComponent>(storage, out var reqAttune))
|
||||
{
|
||||
if (!_attuning.IsAttunedTo(mindId, storage))
|
||||
return false;
|
||||
}
|
||||
|
||||
_actions.GrantActions(user, storage.Comp.SpellEntities, storage);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void OnRemovedAttune(Entity<CP14SpellStorageRequireAttuneComponent> ent, ref RemovedAttuneFromMindEvent args)
|
||||
{
|
||||
if (args.User is null)
|
||||
return;
|
||||
|
||||
_actions.RemoveProvidedActions(args.User.Value, ent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
namespace Content.Shared._CP14.MagicSpellStorage.Components;
|
||||
|
||||
/// <summary>
|
||||
/// The ability to access spellcasting is limited by the attuning requirement
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SpellStorageSystem))]
|
||||
public sealed partial class CP14SpellStorageRequireAttuneComponent : Component
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared._CP14.ResearchTable;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class CP14ResearchTableComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public float ResearchSpeed = 3f;
|
||||
|
||||
[DataField]
|
||||
public float ResearchRadius = 0.5f;
|
||||
|
||||
[DataField]
|
||||
public SoundSpecifier ResearchSound = new SoundCollectionSpecifier("PaperScribbles");
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.ResearchTable;
|
||||
|
||||
public abstract class CP14SharedResearchSystem : EntitySystem
|
||||
{
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CP14ResearchDoAfterEvent : DoAfterEvent
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public ProtoId<CP14SkillPrototype> Skill = default!;
|
||||
|
||||
public override DoAfterEvent Clone() => this;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.RoundStatistic;
|
||||
|
||||
[Prototype("statisticTracker")]
|
||||
public sealed partial class CP14RoundStatTrackerPrototype : IPrototype
|
||||
{
|
||||
[IdDataField] public string ID { get; } = default!;
|
||||
|
||||
[DataField(required: true)]
|
||||
public LocId Text;
|
||||
}
|
||||
22
Content.Shared/_CP14/Skill/CP14LearnSkillsSpecial.cs
Normal file
22
Content.Shared/_CP14/Skill/CP14LearnSkillsSpecial.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill;
|
||||
|
||||
public sealed partial class CP14LearnSkillsSpecial : JobSpecial
|
||||
{
|
||||
[DataField]
|
||||
public HashSet<ProtoId<CP14SkillPrototype>> Skills { get; private set; } = new();
|
||||
|
||||
public override void AfterEquip(EntityUid mob)
|
||||
{
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
var skillSys = entMan.System<CP14SharedSkillSystem>();
|
||||
|
||||
foreach (var skill in Skills)
|
||||
{
|
||||
skillSys.TryAddSkill(mob, skill, free: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
61
Content.Shared/_CP14/Skill/CP14ResearchTableUI.cs
Normal file
61
Content.Shared/_CP14/Skill/CP14ResearchTableUI.cs
Normal file
@@ -0,0 +1,61 @@
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.Skill;
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public enum CP14ResearchTableUiKey
|
||||
{
|
||||
Key,
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class CP14ResearchMessage(ProtoId<CP14SkillPrototype> skill) : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly ProtoId<CP14SkillPrototype> Skill = skill;
|
||||
}
|
||||
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class CP14ResearchTableUiState(List<CP14ResearchUiEntry> skills) : BoundUserInterfaceState
|
||||
{
|
||||
public readonly List<CP14ResearchUiEntry> Skills = skills;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public readonly struct CP14ResearchUiEntry(ProtoId<CP14SkillPrototype> protoId, bool craftable) : IEquatable<CP14ResearchUiEntry>
|
||||
{
|
||||
public readonly ProtoId<CP14SkillPrototype> ProtoId = protoId;
|
||||
public readonly bool Craftable = craftable;
|
||||
|
||||
public int CompareTo(CP14ResearchUiEntry other)
|
||||
{
|
||||
return Craftable.CompareTo(other.Craftable);
|
||||
}
|
||||
|
||||
public override bool Equals(object? obj)
|
||||
{
|
||||
return obj is CP14ResearchUiEntry other && Equals(other);
|
||||
}
|
||||
|
||||
public bool Equals(CP14ResearchUiEntry other)
|
||||
{
|
||||
return ProtoId.Id == other.ProtoId.Id;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return HashCode.Combine(ProtoId, Craftable);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{ProtoId} ({Craftable})";
|
||||
}
|
||||
|
||||
public static int CompareTo(CP14ResearchUiEntry left, CP14ResearchUiEntry right)
|
||||
{
|
||||
return right.CompareTo(left);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Content.Shared._CP14.Skill.Components;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
@@ -7,12 +9,39 @@ namespace Content.Shared._CP14.Skill;
|
||||
|
||||
public abstract partial class CP14SharedSkillSystem : EntitySystem
|
||||
{
|
||||
private EntityQuery<CP14SkillStorageComponent> _skillStorageQuery = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_skillStorageQuery = GetEntityQuery<CP14SkillStorageComponent>();
|
||||
|
||||
SubscribeLocalEvent<CP14SkillStorageComponent, MapInitEvent>(OnMapInit);
|
||||
|
||||
InitializeAdmin();
|
||||
InitializeChecks();
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<CP14SkillStorageComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
//If at initialization we have any skill records, we automatically give them to this entity
|
||||
|
||||
var free = ent.Comp.FreeLearnedSkills.ToList();
|
||||
var learned = ent.Comp.LearnedSkills.ToList();
|
||||
|
||||
ent.Comp.FreeLearnedSkills.Clear();
|
||||
ent.Comp.LearnedSkills.Clear();
|
||||
|
||||
foreach (var skill in free)
|
||||
{
|
||||
TryAddSkill(ent.Owner, skill, ent.Comp, true);
|
||||
}
|
||||
|
||||
foreach (var skill in learned)
|
||||
{
|
||||
TryAddSkill(ent.Owner, skill, ent.Comp);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -20,7 +49,8 @@ public abstract partial class CP14SharedSkillSystem : EntitySystem
|
||||
/// </summary>
|
||||
public bool TryAddSkill(EntityUid target,
|
||||
ProtoId<CP14SkillPrototype> skill,
|
||||
CP14SkillStorageComponent? component = null)
|
||||
CP14SkillStorageComponent? component = null,
|
||||
bool free = false)
|
||||
{
|
||||
if (!Resolve(target, ref component, false))
|
||||
return false;
|
||||
@@ -31,15 +61,22 @@ public abstract partial class CP14SharedSkillSystem : EntitySystem
|
||||
if (!_proto.TryIndex(skill, out var indexedSkill))
|
||||
return false;
|
||||
|
||||
if (indexedSkill.Effect is not null)
|
||||
foreach (var effect in indexedSkill.Effects)
|
||||
{
|
||||
indexedSkill.Effect.AddSkill(EntityManager, target);
|
||||
effect.AddSkill(EntityManager, target);
|
||||
}
|
||||
|
||||
component.SkillsSumExperience += indexedSkill.LearnCost;
|
||||
if (free)
|
||||
component.FreeLearnedSkills.Add(skill);
|
||||
else
|
||||
component.SkillsSumExperience += indexedSkill.LearnCost;
|
||||
|
||||
component.LearnedSkills.Add(skill);
|
||||
Dirty(target, component);
|
||||
|
||||
var learnEv = new CP14SkillLearnedEvent(skill, target);
|
||||
RaiseLocalEvent(target, ref learnEv);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -59,12 +96,13 @@ public abstract partial class CP14SharedSkillSystem : EntitySystem
|
||||
if (!_proto.TryIndex(skill, out var indexedSkill))
|
||||
return false;
|
||||
|
||||
if (indexedSkill.Effect is not null)
|
||||
foreach (var effect in indexedSkill.Effects)
|
||||
{
|
||||
indexedSkill.Effect.RemoveSkill(EntityManager, target);
|
||||
effect.RemoveSkill(EntityManager, target);
|
||||
}
|
||||
|
||||
component.SkillsSumExperience -= indexedSkill.LearnCost;
|
||||
if (!component.FreeLearnedSkills.Remove(skill))
|
||||
component.SkillsSumExperience -= indexedSkill.LearnCost;
|
||||
|
||||
Dirty(target, component);
|
||||
return true;
|
||||
@@ -83,53 +121,14 @@ public abstract partial class CP14SharedSkillSystem : EntitySystem
|
||||
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,
|
||||
public bool HaveFreeSkill(EntityUid target,
|
||||
ProtoId<CP14SkillPrototype> skill,
|
||||
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;
|
||||
return component.FreeLearnedSkills.Contains(skill);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -158,12 +157,6 @@ public abstract partial class CP14SharedSkillSystem : EntitySystem
|
||||
if (!AllowedToLearn(target, skill, component))
|
||||
return false;
|
||||
|
||||
//Experience check
|
||||
if (!component.Progress.TryGetValue(skill.Tree, out var currentExp))
|
||||
return false;
|
||||
if (currentExp < skill.LearnCost)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -182,13 +175,13 @@ public abstract partial class CP14SharedSkillSystem : EntitySystem
|
||||
return false;
|
||||
|
||||
//Check max cap
|
||||
if (component.SkillsSumExperience + skill.LearnCost >= component.ExperienceMaxCap)
|
||||
if (component.SkillsSumExperience + skill.LearnCost > component.ExperienceMaxCap)
|
||||
return false;
|
||||
|
||||
//Restrictions check
|
||||
foreach (var req in skill.Restrictions)
|
||||
{
|
||||
if (!req.Check(EntityManager, target))
|
||||
if (!req.Check(EntityManager, target, skill))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -205,15 +198,9 @@ public abstract partial class CP14SharedSkillSystem : EntitySystem
|
||||
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;
|
||||
|
||||
@@ -228,11 +215,11 @@ public abstract partial class CP14SharedSkillSystem : EntitySystem
|
||||
if (!_proto.TryIndex(skill, out var indexedSkill))
|
||||
return string.Empty;
|
||||
|
||||
if (indexedSkill.Name != null)
|
||||
if (indexedSkill.Name is not null)
|
||||
return Loc.GetString(indexedSkill.Name);
|
||||
|
||||
if (indexedSkill.Effect != null)
|
||||
return indexedSkill.Effect.GetName(EntityManager, _proto) ?? string.Empty;
|
||||
if (indexedSkill.Effects.Count > 0)
|
||||
return indexedSkill.Effects.First().GetName(EntityManager, _proto) ?? string.Empty;
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
@@ -245,12 +232,19 @@ public abstract partial class CP14SharedSkillSystem : EntitySystem
|
||||
if (!_proto.TryIndex(skill, out var indexedSkill))
|
||||
return string.Empty;
|
||||
|
||||
if (indexedSkill.Desc != null)
|
||||
if (indexedSkill.Desc is not null)
|
||||
return Loc.GetString(indexedSkill.Desc);
|
||||
|
||||
if (indexedSkill.Effect != null)
|
||||
return indexedSkill.Effect.GetDescription(EntityManager, _proto) ?? string.Empty;
|
||||
var sb = new StringBuilder();
|
||||
|
||||
return string.Empty;
|
||||
foreach (var effect in indexedSkill.Effects)
|
||||
{
|
||||
sb.Append(effect.GetDescription(EntityManager, _proto, skill) + "\n");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[ByRefEvent]
|
||||
public record struct CP14SkillLearnedEvent(ProtoId<CP14SkillPrototype> Skill, EntityUid User);
|
||||
|
||||
@@ -50,27 +50,6 @@ public abstract partial class CP14SharedSkillSystem
|
||||
|
||||
var target = args.Target;
|
||||
|
||||
//Add skill points
|
||||
foreach (var tree in _allTrees)
|
||||
{
|
||||
FixedPoint2 current = 0;
|
||||
ent.Comp.Progress.TryGetValue(tree, out current);
|
||||
|
||||
var name = Loc.GetString(tree.Name);
|
||||
args.Verbs.Add(new Verb
|
||||
{
|
||||
Text = name,
|
||||
Message = $"{name} EXP {current} -> {current + 1}",
|
||||
Category = VerbCategory.CP14AdminSkillAdd,
|
||||
Icon = tree.Icon,
|
||||
Act = () =>
|
||||
{
|
||||
TryAddExperience(target, tree.ID, 1);
|
||||
},
|
||||
Priority = 2,
|
||||
});
|
||||
}
|
||||
|
||||
//Add Skill
|
||||
foreach (var skill in _allSkills)
|
||||
{
|
||||
@@ -91,30 +70,6 @@ public abstract partial class CP14SharedSkillSystem
|
||||
});
|
||||
}
|
||||
|
||||
//Remove skill points
|
||||
foreach (var tree in _allTrees)
|
||||
{
|
||||
FixedPoint2 current = 0;
|
||||
ent.Comp.Progress.TryGetValue(tree, out current);
|
||||
|
||||
if (current < 1)
|
||||
continue;
|
||||
|
||||
var name = Loc.GetString(tree.Name);
|
||||
args.Verbs.Add(new Verb
|
||||
{
|
||||
Text = name,
|
||||
Message = $"{name} EXP {current} -> {current - 1}",
|
||||
Category = VerbCategory.CP14AdminSkillRemove,
|
||||
Icon = tree.Icon,
|
||||
Act = () =>
|
||||
{
|
||||
TryRemoveExperience(target, tree.ID, 1);
|
||||
},
|
||||
Priority = 2,
|
||||
});
|
||||
}
|
||||
|
||||
//Remove Skill
|
||||
foreach (var skill in ent.Comp.LearnedSkills)
|
||||
{
|
||||
|
||||
75
Content.Shared/_CP14/Skill/CP14SkillSystem.Checks.cs
Normal file
75
Content.Shared/_CP14/Skill/CP14SkillSystem.Checks.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System.Text;
|
||||
using Content.Shared._CP14.Skill.Components;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Throwing;
|
||||
using Content.Shared.Weapons.Melee.Events;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Shared._CP14.Skill;
|
||||
|
||||
public abstract partial class CP14SharedSkillSystem
|
||||
{
|
||||
[Dependency] private readonly ThrowingSystem _throwing = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SharedHandsSystem _hands = default!;
|
||||
[Dependency] private readonly DamageableSystem _damageable = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
private void InitializeChecks()
|
||||
{
|
||||
SubscribeLocalEvent<CP14MeleeWeaponSkillRequiredComponent, MeleeHitEvent>(OnMeleeAttack);
|
||||
SubscribeLocalEvent<CP14MeleeWeaponSkillRequiredComponent, ExaminedEvent>(OnExamined);
|
||||
}
|
||||
|
||||
private void OnExamined(Entity<CP14MeleeWeaponSkillRequiredComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(Loc.GetString("cp14-skill-issue-title") + "\n");
|
||||
|
||||
foreach (var skill in ent.Comp.Skills)
|
||||
{
|
||||
if (!_proto.TryIndex(skill, out var indexedSkill))
|
||||
continue;
|
||||
|
||||
if (indexedSkill.Name is null)
|
||||
continue;
|
||||
|
||||
var color = HaveSkill(args.Examiner, skill) ? Color.LimeGreen.ToHex() : Color.Red.ToHex();
|
||||
sb.Append($"[color={color}] - {Loc.GetString(indexedSkill.Name)} [/color]\n");
|
||||
}
|
||||
args.PushMarkup(sb.ToString());
|
||||
}
|
||||
|
||||
private void OnMeleeAttack(Entity<CP14MeleeWeaponSkillRequiredComponent> ent, ref MeleeHitEvent args)
|
||||
{
|
||||
if (!_skillStorageQuery.TryComp(args.User, out var skillStorage))
|
||||
return;
|
||||
|
||||
var passed = true;
|
||||
foreach (var reqSkill in ent.Comp.Skills)
|
||||
{
|
||||
if (!skillStorage.LearnedSkills.Contains(reqSkill))
|
||||
{
|
||||
passed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
args.BonusDamage *= ent.Comp.DamageMultiplier;
|
||||
|
||||
if (_net.IsClient)
|
||||
return;
|
||||
|
||||
if (passed || !_random.Prob(ent.Comp.DropProbability))
|
||||
return;
|
||||
|
||||
_hands.TryDrop(args.User, ent);
|
||||
_throwing.TryThrow(ent, _random.NextAngle().ToWorldVec() * 2, 2f, args.User);
|
||||
_damageable.TryChangeDamage(args.User, args.BaseDamage);
|
||||
_popup.PopupEntity(Loc.GetString("cp14-skill-issue"), args.User, args.User, PopupType.Medium);
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
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,31 @@
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
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 CP14MeleeWeaponSkillRequiredComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// What skills does a character have to have to use this weapon?
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public HashSet<ProtoId<CP14SkillPrototype>> Skills = new();
|
||||
|
||||
/// <summary>
|
||||
/// The chances of dropping a weapon from your hands if the required skills are not learned by the character.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public float DropProbability = 0.5f;
|
||||
|
||||
/// <summary>
|
||||
/// Reduces outgoing damage if the required skills are not learned by the character
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public float DamageMultiplier = 0.5f;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared._CP14.ResearchTable;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameStates;
|
||||
@@ -10,29 +11,36 @@ namespace Content.Shared._CP14.Skill.Components;
|
||||
/// Component that stores the skills learned by a player and their progress in the skill trees.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
|
||||
[Access(typeof(CP14SharedSkillSystem))]
|
||||
[Access(typeof(CP14SharedSkillSystem), typeof(CP14SharedResearchSystem))]
|
||||
public sealed partial class CP14SkillStorageComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Tracks skills that are learned without spending memory points.
|
||||
/// the skills that are here are DUBLED in the LearnedSkills,
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public List<ProtoId<CP14SkillPrototype>> FreeLearnedSkills = new();
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public List<ProtoId<CP14SkillPrototype>> LearnedSkills = new();
|
||||
|
||||
/// <summary>
|
||||
/// skills that the player has learned on the research table, but has not yet learned in the skill tree.
|
||||
/// </summary>
|
||||
[DataField, AutoNetworkedField]
|
||||
public List<ProtoId<CP14SkillPrototype>> ResearchedSkills = 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;
|
||||
public FixedPoint2 ExperienceMaxCap = 5;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared.Actions;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
@@ -39,7 +40,7 @@ public sealed partial class AddAction : CP14SkillEffect
|
||||
return !protoManager.TryIndex(Action, out var indexedAction) ? string.Empty : indexedAction.Name;
|
||||
}
|
||||
|
||||
public override string? GetDescription(IEntityManager entMagager, IPrototypeManager protoManager)
|
||||
public override string? GetDescription(IEntityManager entMagager, IPrototypeManager protoManager, ProtoId<CP14SkillPrototype> skill)
|
||||
{
|
||||
return !protoManager.TryIndex(Action, out var indexedAction) ? string.Empty : indexedAction.Description;
|
||||
}
|
||||
|
||||
31
Content.Shared/_CP14/Skill/Effects/AddComponents.cs
Normal file
31
Content.Shared/_CP14/Skill/Effects/AddComponents.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Effects;
|
||||
|
||||
public sealed partial class AddComponents : CP14SkillEffect
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public ComponentRegistry Components = new();
|
||||
|
||||
public override void AddSkill(IEntityManager entManager, EntityUid target)
|
||||
{
|
||||
entManager.AddComponents(target, Components);
|
||||
}
|
||||
|
||||
public override void RemoveSkill(IEntityManager entManager, EntityUid target)
|
||||
{
|
||||
entManager.RemoveComponents(target, Components);
|
||||
}
|
||||
|
||||
public override string? GetName(IEntityManager entMagager, IPrototypeManager protoManager)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string? GetDescription(IEntityManager entMagager, IPrototypeManager protoManager, ProtoId<CP14SkillPrototype> skill)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
33
Content.Shared/_CP14/Skill/Effects/AddMaxMana.cs
Normal file
33
Content.Shared/_CP14/Skill/Effects/AddMaxMana.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Content.Shared._CP14.MagicEnergy;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Effects;
|
||||
|
||||
public sealed partial class AddManaMax : CP14SkillEffect
|
||||
{
|
||||
[DataField]
|
||||
public FixedPoint2 AdditionalMana = 0;
|
||||
public override void AddSkill(IEntityManager entManager, EntityUid target)
|
||||
{
|
||||
var magicSystem = entManager.System<SharedCP14MagicEnergySystem>();
|
||||
magicSystem.ChangeMaximumEnergy(target, AdditionalMana);
|
||||
}
|
||||
|
||||
public override void RemoveSkill(IEntityManager entManager, EntityUid target)
|
||||
{
|
||||
var magicSystem = entManager.System<SharedCP14MagicEnergySystem>();
|
||||
magicSystem.ChangeMaximumEnergy(target, -AdditionalMana);
|
||||
}
|
||||
|
||||
public override string? GetName(IEntityManager entMagager, IPrototypeManager protoManager)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string? GetDescription(IEntityManager entMagager, IPrototypeManager protoManager, ProtoId<CP14SkillPrototype> skill)
|
||||
{
|
||||
return Loc.GetString("cp14-skill-desc-add-mana", ("mana", AdditionalMana.ToString()));
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
@@ -13,5 +14,5 @@ public abstract partial class CP14SkillEffect
|
||||
|
||||
public abstract string? GetName(IEntityManager entMagager, IPrototypeManager protoManager);
|
||||
|
||||
public abstract string? GetDescription(IEntityManager entMagager, IPrototypeManager protoManager);
|
||||
public abstract string? GetDescription(IEntityManager entMagager, IPrototypeManager protoManager, ProtoId<CP14SkillPrototype> skill);
|
||||
}
|
||||
|
||||
78
Content.Shared/_CP14/Skill/Effects/ModifyManacost.cs
Normal file
78
Content.Shared/_CP14/Skill/Effects/ModifyManacost.cs
Normal file
@@ -0,0 +1,78 @@
|
||||
using System.Text;
|
||||
using Content.Shared._CP14.MagicManacostModify;
|
||||
using Content.Shared._CP14.MagicRitual.Prototypes;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Effects;
|
||||
|
||||
public sealed partial class ModifyManacost : CP14SkillEffect
|
||||
{
|
||||
[DataField]
|
||||
public FixedPoint2 Global = 0f;
|
||||
|
||||
[DataField]
|
||||
public Dictionary<ProtoId<CP14MagicTypePrototype>, FixedPoint2> Modifiers = new();
|
||||
|
||||
public override void AddSkill(IEntityManager entManager, EntityUid target)
|
||||
{
|
||||
entManager.EnsureComponent<CP14MagicManacostModifyComponent>(target, out var magicEffectManaCost);
|
||||
|
||||
foreach (var (magicType, modifier) in Modifiers)
|
||||
{
|
||||
if (!magicEffectManaCost.Modifiers.ContainsKey(magicType))
|
||||
magicEffectManaCost.Modifiers.Add(magicType, 1 + modifier);
|
||||
else
|
||||
magicEffectManaCost.Modifiers[magicType] += modifier;
|
||||
}
|
||||
magicEffectManaCost.GlobalModifier += Global;
|
||||
}
|
||||
|
||||
public override void RemoveSkill(IEntityManager entManager, EntityUid target)
|
||||
{
|
||||
entManager.EnsureComponent<CP14MagicManacostModifyComponent>(target, out var magicEffectManaCost);
|
||||
|
||||
foreach (var (magicType, modifier) in Modifiers)
|
||||
{
|
||||
if (!magicEffectManaCost.Modifiers.ContainsKey(magicType))
|
||||
continue;
|
||||
|
||||
magicEffectManaCost.Modifiers[magicType] -= modifier;
|
||||
if (magicEffectManaCost.Modifiers[magicType] <= 0)
|
||||
magicEffectManaCost.Modifiers.Remove(magicType);
|
||||
}
|
||||
magicEffectManaCost.GlobalModifier -= Global;
|
||||
}
|
||||
|
||||
public override string? GetName(IEntityManager entMagager, IPrototypeManager protoManager)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string? GetDescription(IEntityManager entMagager, IPrototypeManager protoManager, ProtoId<CP14SkillPrototype> skill)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(Loc.GetString("cp14-clothing-magic-examine")+"\n");
|
||||
|
||||
if (Global != 0)
|
||||
{
|
||||
|
||||
var plus = (float)Global > 0 ? "+" : "";
|
||||
sb.Append(
|
||||
$"{Loc.GetString("cp14-clothing-magic-global")}: {plus}{MathF.Round((float)Global * 100, MidpointRounding.AwayFromZero)}%\n");
|
||||
}
|
||||
|
||||
foreach (var modifier in Modifiers)
|
||||
{
|
||||
if (modifier.Value == 0)
|
||||
continue;
|
||||
|
||||
var plus = modifier.Value > 1 ? "+" : "";
|
||||
var indexedType = protoManager.Index(modifier.Key);
|
||||
sb.Append($"- [color={indexedType.Color.ToHex()}]{Loc.GetString(indexedType.Name)}[/color]: {plus}{modifier.Value*100}%");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared.Actions;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
@@ -62,7 +63,7 @@ public sealed partial class ReplaceAction : CP14SkillEffect
|
||||
return !protoManager.TryIndex(NewAction, out var indexedAction) ? string.Empty : indexedAction.Name;
|
||||
}
|
||||
|
||||
public override string? GetDescription(IEntityManager entMagager, IPrototypeManager protoManager)
|
||||
public override string? GetDescription(IEntityManager entMagager, IPrototypeManager protoManager, ProtoId<CP14SkillPrototype> skill)
|
||||
{
|
||||
return !protoManager.TryIndex(NewAction, out var indexedAction) ? string.Empty : indexedAction.Description;
|
||||
}
|
||||
|
||||
65
Content.Shared/_CP14/Skill/Effects/UnlockRecipes.cs
Normal file
65
Content.Shared/_CP14/Skill/Effects/UnlockRecipes.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System.Text;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared._CP14.Workbench.Prototypes;
|
||||
using Content.Shared._CP14.Workbench.Requirements;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Effects;
|
||||
|
||||
/// <summary>
|
||||
/// This effect only exists for parsing the description.
|
||||
/// </summary>
|
||||
public sealed partial class UnlockRecipes : CP14SkillEffect
|
||||
{
|
||||
public override void AddSkill(IEntityManager entManager, EntityUid target)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public override void RemoveSkill(IEntityManager entManager, EntityUid target)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
public override string? GetName(IEntityManager entMagager, IPrototypeManager protoManager)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public override string? GetDescription(IEntityManager entMagager, IPrototypeManager protoManager, ProtoId<CP14SkillPrototype> skill)
|
||||
{
|
||||
var allRecipes = protoManager.EnumeratePrototypes<CP14WorkbenchRecipePrototype>();
|
||||
|
||||
var sb = new StringBuilder();
|
||||
sb.Append(Loc.GetString("cp14-skill-desc-unlock-recipes") + "\n");
|
||||
|
||||
var affectedRecipes = new List<CP14WorkbenchRecipePrototype>();
|
||||
foreach (var recipe in allRecipes)
|
||||
{
|
||||
foreach (var req in recipe.Requirements)
|
||||
{
|
||||
switch (req)
|
||||
{
|
||||
case SkillRequired skillReq:
|
||||
foreach (var skillReqSkill in skillReq.Skills)
|
||||
{
|
||||
if (skillReqSkill == skill)
|
||||
{
|
||||
affectedRecipes.Add(recipe);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (var recipe in affectedRecipes)
|
||||
{
|
||||
if (!protoManager.TryIndex(recipe.Result, out var indexedResult))
|
||||
continue;
|
||||
sb.Append("- " + indexedResult.Name + "\n");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
@@ -18,13 +18,13 @@ public sealed partial class CP14SkillPrototype : IPrototype
|
||||
/// Skill Title. If you leave null, the name will try to generate from Effect.GetName()
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public LocId? Name;
|
||||
public LocId? Name = null;
|
||||
|
||||
/// <summary>
|
||||
/// Skill Description. If you leave null, the description will try to generate from Effect.GetDescription()
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public LocId? Desc;
|
||||
public LocId? Desc = null;
|
||||
|
||||
/// <summary>
|
||||
/// The tree this skill belongs to. This is used to group skills together in the UI.
|
||||
@@ -55,7 +55,7 @@ public sealed partial class CP14SkillPrototype : IPrototype
|
||||
/// But the presence of the skill itself can affect some systems that check for the presence of certain skills.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public CP14SkillEffect? Effect;
|
||||
public List<CP14SkillEffect> Effects = new();
|
||||
|
||||
/// <summary>
|
||||
/// Skill restriction. Limiters on learning. Any reason why a player cannot learn this skill.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
@@ -7,7 +8,7 @@ namespace Content.Shared._CP14.Skill.Restrictions;
|
||||
[MeansImplicitUse]
|
||||
public abstract partial class CP14SkillRestriction
|
||||
{
|
||||
public abstract bool Check(IEntityManager entManager, EntityUid target);
|
||||
public abstract bool Check(IEntityManager entManager, EntityUid target, CP14SkillPrototype skill);
|
||||
|
||||
public abstract string GetDescription(IEntityManager entManager, IPrototypeManager protoManager);
|
||||
}
|
||||
|
||||
18
Content.Shared/_CP14/Skill/Restrictions/Impossible.cs
Normal file
18
Content.Shared/_CP14/Skill/Restrictions/Impossible.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Content.Shared._CP14.Skill.Components;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Restrictions;
|
||||
|
||||
public sealed partial class Impossible : CP14SkillRestriction
|
||||
{
|
||||
public override bool Check(IEntityManager entManager, EntityUid target, CP14SkillPrototype skill)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public override string GetDescription(IEntityManager entManager, IPrototypeManager protoManager)
|
||||
{
|
||||
return Loc.GetString("cp14-skill-req-impossible");
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ public sealed partial class NeedPrerequisite : CP14SkillRestriction
|
||||
[DataField(required: true)]
|
||||
public ProtoId<CP14SkillPrototype> Prerequisite = new();
|
||||
|
||||
public override bool Check(IEntityManager entManager, EntityUid target)
|
||||
public override bool Check(IEntityManager entManager, EntityUid target, CP14SkillPrototype skill)
|
||||
{
|
||||
if (!entManager.TryGetComponent<CP14SkillStorageComponent>(target, out var skillStorage))
|
||||
return false;
|
||||
|
||||
26
Content.Shared/_CP14/Skill/Restrictions/Researched.cs
Normal file
26
Content.Shared/_CP14/Skill/Restrictions/Researched.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Content.Shared._CP14.Skill.Components;
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared._CP14.Workbench;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.Skill.Restrictions;
|
||||
|
||||
public sealed partial class Researched : CP14SkillRestriction
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public List<CP14WorkbenchCraftRequirement> Requirements = new();
|
||||
|
||||
public override bool Check(IEntityManager entManager, EntityUid target, CP14SkillPrototype skill)
|
||||
{
|
||||
if (!entManager.TryGetComponent<CP14SkillStorageComponent>(target, out var skillStorage))
|
||||
return false;
|
||||
|
||||
var learned = skillStorage.ResearchedSkills;
|
||||
return learned.Contains(skill);
|
||||
}
|
||||
|
||||
public override string GetDescription(IEntityManager entManager, IPrototypeManager protoManager)
|
||||
{
|
||||
return Loc.GetString("cp14-skill-req-researched");
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
using Content.Shared._CP14.Skill.Prototypes;
|
||||
using Content.Shared.Humanoid;
|
||||
using Content.Shared.Humanoid.Prototypes;
|
||||
using Robust.Shared.Prototypes;
|
||||
@@ -9,7 +10,7 @@ public sealed partial class SpeciesWhitelist : CP14SkillRestriction
|
||||
[DataField(required: true)]
|
||||
public ProtoId<SpeciesPrototype> Species = new();
|
||||
|
||||
public override bool Check(IEntityManager entManager, EntityUid target)
|
||||
public override bool Check(IEntityManager entManager, EntityUid target, CP14SkillPrototype skill)
|
||||
{
|
||||
if (!entManager.TryGetComponent<HumanoidAppearanceComponent>(target, out var appearance))
|
||||
return false;
|
||||
|
||||
@@ -10,7 +10,7 @@ using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.Workbench;
|
||||
|
||||
public abstract class SharedCP14WorkbenchSystem : EntitySystem
|
||||
public abstract class CP14SharedWorkbenchSystem : EntitySystem
|
||||
{
|
||||
}
|
||||
|
||||
@@ -26,8 +26,7 @@ public sealed partial class MaterialResource : CP14WorkbenchCraftRequirement
|
||||
EntityManager entManager,
|
||||
IPrototypeManager protoManager,
|
||||
HashSet<EntityUid> placedEntities,
|
||||
EntityUid user,
|
||||
CP14WorkbenchRecipePrototype recipe)
|
||||
EntityUid user)
|
||||
{
|
||||
var count = 0;
|
||||
foreach (var ent in placedEntities)
|
||||
@@ -76,12 +75,14 @@ public sealed partial class MaterialResource : CP14WorkbenchCraftRequirement
|
||||
if (mat.Key != Material)
|
||||
continue;
|
||||
|
||||
if (requiredCount <= 0)
|
||||
return;
|
||||
|
||||
if (stack is null)
|
||||
{
|
||||
var value = (int)MathF.Min(requiredCount, mat.Value);
|
||||
requiredCount -= value;
|
||||
entManager.DeleteEntity(placedEntity);
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -22,8 +22,7 @@ public sealed partial class ProtoIdResource : CP14WorkbenchCraftRequirement
|
||||
public override bool CheckRequirement(EntityManager entManager,
|
||||
IPrototypeManager protoManager,
|
||||
HashSet<EntityUid> placedEntities,
|
||||
EntityUid user,
|
||||
CP14WorkbenchRecipePrototype recipe)
|
||||
EntityUid user)
|
||||
{
|
||||
var indexedIngredients = IndexIngredients(entManager, placedEntities);
|
||||
|
||||
|
||||
@@ -16,8 +16,7 @@ public sealed partial class SkillRequired : CP14WorkbenchCraftRequirement
|
||||
public override bool CheckRequirement(EntityManager entManager,
|
||||
IPrototypeManager protoManager,
|
||||
HashSet<EntityUid> placedEntities,
|
||||
EntityUid user,
|
||||
CP14WorkbenchRecipePrototype recipe)
|
||||
EntityUid user)
|
||||
{
|
||||
var knowledgeSystem = entManager.System<CP14SharedSkillSystem>();
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user