Compare commits
146 Commits
ed-23-07-2
...
ed-06-08-2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a02cebd1de | ||
|
|
78e140b4ae | ||
|
|
1b0bf2ad18 | ||
|
|
dc853b6662 | ||
|
|
37e0ffa173 | ||
|
|
6ab9ca6bd0 | ||
|
|
934c1e44a6 | ||
|
|
818eb30d2d | ||
|
|
12d2af692f | ||
|
|
1f4b7f68bf | ||
|
|
9a07a9a052 | ||
|
|
1633895321 | ||
|
|
0cd3a3c2d9 | ||
|
|
72cbed696f | ||
|
|
c620d66dab | ||
|
|
599c599a4e | ||
|
|
31c9485e3b | ||
|
|
56da23925f | ||
|
|
19365c0314 | ||
|
|
82d89a97f1 | ||
|
|
2bb43245c8 | ||
|
|
909fa27450 | ||
|
|
7478e6b445 | ||
|
|
5072800d4a | ||
|
|
1f587c10b8 | ||
|
|
22bb0ae283 | ||
|
|
c69cb0320e | ||
|
|
02c5e03ae7 | ||
|
|
cc5f27c057 | ||
|
|
fb40f8cd25 | ||
|
|
0d345c33b9 | ||
|
|
9011aab26b | ||
|
|
cf6b42d20c | ||
|
|
655b32b720 | ||
|
|
fce5269fc0 | ||
|
|
2951ea2bee | ||
|
|
79fa810b9c | ||
|
|
ab84eee083 | ||
|
|
1d55a439ff | ||
|
|
4a9bd17a86 | ||
|
|
d9286dd6d9 | ||
|
|
e1e2d26969 | ||
|
|
3a10ffa030 | ||
|
|
404743f073 | ||
|
|
925d1e3ac8 | ||
|
|
7f9e06501f | ||
|
|
255b7f3b7a | ||
|
|
093054f7e3 | ||
|
|
e3d7c1bd6e | ||
|
|
845fa31419 | ||
|
|
34a7aa70ce | ||
|
|
3283424ba8 | ||
|
|
54e42cc4e5 | ||
|
|
9bd623a927 | ||
|
|
d846a621e5 | ||
|
|
dc1be42b8f | ||
|
|
6a1efebb6a | ||
|
|
de7df2a760 | ||
|
|
f49fc5a89c | ||
|
|
f67f7034b9 | ||
|
|
b66c286ecb | ||
|
|
9f6e5e8d60 | ||
|
|
1146f2fefe | ||
|
|
b9090e84f7 | ||
|
|
45a481de47 | ||
|
|
5485ae25e0 | ||
|
|
1149290825 | ||
|
|
d5d8c14ced | ||
|
|
8f250581be | ||
|
|
e7aa7791b4 | ||
|
|
7c7f4a9f25 | ||
|
|
582e6d2010 | ||
|
|
b1d5436bcd | ||
|
|
18506e1f3b | ||
|
|
e72393df71 | ||
|
|
eab5030c39 | ||
|
|
811da0e3d6 | ||
|
|
a7fa66e956 | ||
|
|
f083d080f5 | ||
|
|
5905767ce7 | ||
|
|
a99ae6211d | ||
|
|
76096b21f1 | ||
|
|
333bb386d9 | ||
|
|
4e1fe975ec | ||
|
|
44199991bf | ||
|
|
af47cbd7b0 | ||
|
|
d5236d8236 | ||
|
|
ff581d4275 | ||
|
|
0a07203121 | ||
|
|
818f43b005 | ||
|
|
d1663cade4 | ||
|
|
769967ac36 | ||
|
|
6f7719011a | ||
|
|
e161a021c4 | ||
|
|
2a7883b92e | ||
|
|
7388b91ef5 | ||
|
|
6f2e1d6d9f | ||
|
|
e95aaef839 | ||
|
|
bcd7a7ad00 | ||
|
|
f56e4f6624 | ||
|
|
99854edc93 | ||
|
|
50ba20c766 | ||
|
|
8de6b74e08 | ||
|
|
2d124c5c29 | ||
|
|
61efd1201e | ||
|
|
b0cc97fb04 | ||
|
|
0d12ce54d4 | ||
|
|
8f6326c3e0 | ||
|
|
b6811d3570 | ||
|
|
06d136698c | ||
|
|
50e042011d | ||
|
|
54e760088a | ||
|
|
620aed5939 | ||
|
|
f210325460 | ||
|
|
9def96d762 | ||
|
|
687e2c5844 | ||
|
|
bd4020bdfc | ||
|
|
ee641c2dff | ||
|
|
4536a527df | ||
|
|
492fb529df | ||
|
|
aa886ca494 | ||
|
|
08f1aa9fa1 | ||
|
|
bb20f3a1bc | ||
|
|
c4dcc90972 | ||
|
|
688a46f903 | ||
|
|
9c84ce9be0 | ||
|
|
343496faf8 | ||
|
|
fc0954085f | ||
|
|
8b27ef8a78 | ||
|
|
bf93349b73 | ||
|
|
e1f3bdc748 | ||
|
|
4f8b634f38 | ||
|
|
a32f9ff711 | ||
|
|
c5a6f75def | ||
|
|
8c477a67c1 | ||
|
|
3b5e0003c3 | ||
|
|
ea753e5227 | ||
|
|
ec071ceca7 | ||
|
|
7381df4335 | ||
|
|
e7aa97645b | ||
|
|
3187006641 | ||
|
|
526238bac5 | ||
|
|
f348213750 | ||
|
|
ed3e896cb8 | ||
|
|
0190e366a3 | ||
|
|
9826b9ff38 |
14
.github/FUNDING.yml
vendored
Normal file
14
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
# These are supported funding model platforms
|
||||
|
||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
||||
patreon: # Replace with a single Patreon username
|
||||
open_collective: # Replace with a single Open Collective username
|
||||
ko_fi: # Replace with a single Ko-fi username
|
||||
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
||||
liberapay: # Replace with a single Liberapay username
|
||||
issuehunt: # Replace with a single IssueHunt username
|
||||
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
|
||||
polar: # Replace with a single Polar username
|
||||
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
|
||||
custom: ['https://boosty.to/theshued']
|
||||
4
.github/labeler.yml
vendored
4
.github/labeler.yml
vendored
@@ -12,6 +12,10 @@
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: '**/*.xaml*'
|
||||
|
||||
"Changes: Shaders":
|
||||
- changed-files:
|
||||
- any-glob-to-any-file: '**/*.swsl'
|
||||
|
||||
"No C#":
|
||||
- changed-files:
|
||||
# Equiv to any-glob-to-all as long as this has one matcher. If ALL changed files are not C# files, then apply label.
|
||||
|
||||
@@ -380,7 +380,7 @@ namespace Content.Client.Arcade
|
||||
{
|
||||
PanelOverride = back,
|
||||
HorizontalExpand = true,
|
||||
SizeFlagsStretchRatio = 60
|
||||
SizeFlagsStretchRatio = 34.25f
|
||||
};
|
||||
var backgroundPanel = new PanelContainer
|
||||
{
|
||||
|
||||
@@ -17,6 +17,7 @@ public sealed class BlockGameBoundUserInterface : BoundUserInterface
|
||||
base.Open();
|
||||
|
||||
_menu = this.CreateWindow<BlockGameMenu>();
|
||||
_menu.OnAction += SendAction;
|
||||
}
|
||||
|
||||
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
|
||||
|
||||
@@ -25,6 +25,7 @@ public sealed class SpaceVillainArcadeBoundUserInterface : BoundUserInterface
|
||||
base.Open();
|
||||
|
||||
_menu = this.CreateWindow<SpaceVillainArcadeMenu>();
|
||||
_menu.OnPlayerAction += SendAction;
|
||||
}
|
||||
|
||||
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
|
||||
|
||||
@@ -85,8 +85,19 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
|
||||
if (protoId == null)
|
||||
return;
|
||||
|
||||
//if (sexMorph)
|
||||
// protoId = HumanoidVisualLayersExtension.GetSexMorph(key, component.Sex, protoId);
|
||||
|
||||
//CP14 female bodies support
|
||||
if (sexMorph)
|
||||
protoId = HumanoidVisualLayersExtension.GetSexMorph(key, component.Sex, protoId);
|
||||
{
|
||||
var tempProto = HumanoidVisualLayersExtension.GetSexMorph(key, component.Sex, protoId);
|
||||
if (_prototypeManager.TryIndex<HumanoidSpeciesSpriteLayer>(tempProto, out _))
|
||||
{
|
||||
protoId = tempProto;
|
||||
}
|
||||
}
|
||||
//CP14 female bodies support end
|
||||
|
||||
var proto = _prototypeManager.Index<HumanoidSpeciesSpriteLayer>(protoId);
|
||||
component.BaseLayers[key] = proto;
|
||||
|
||||
@@ -12,7 +12,7 @@ public sealed partial class MechMenu : FancyWindow
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _ent = default!;
|
||||
|
||||
private readonly EntityUid _mech;
|
||||
private EntityUid _mech;
|
||||
|
||||
public event Action<EntityUid>? OnRemoveButtonPressed;
|
||||
|
||||
@@ -25,6 +25,7 @@ public sealed partial class MechMenu : FancyWindow
|
||||
public void SetEntity(EntityUid uid)
|
||||
{
|
||||
MechView.SetEntity(uid);
|
||||
_mech = uid;
|
||||
}
|
||||
|
||||
public void UpdateMechStats()
|
||||
|
||||
@@ -170,11 +170,12 @@ public sealed partial class ReplaySpectatorSystem
|
||||
{
|
||||
var size = grid.LocalAABB.Size.LengthSquared();
|
||||
|
||||
if (maxSize is not null && size < maxSize)
|
||||
continue;
|
||||
|
||||
var station = HasComp<StationMemberComponent>(uid);
|
||||
|
||||
//We want the first station grid to overwrite any previous non-station grids no matter the size, in case the vgroid was found first
|
||||
if (maxSize is not null && size < maxSize && !(!stationFound && station))
|
||||
continue;
|
||||
|
||||
if (!station && stationFound)
|
||||
continue;
|
||||
|
||||
@@ -183,7 +184,6 @@ public sealed partial class ReplaySpectatorSystem
|
||||
|
||||
if (station)
|
||||
stationFound = true;
|
||||
|
||||
}
|
||||
|
||||
coords = new EntityCoordinates(maxUid ?? default, default);
|
||||
|
||||
@@ -142,8 +142,8 @@ public sealed class CharacterUIController : UIController, IOnStateEntered<Gamepl
|
||||
conditionControl.ProgressTexture.Progress = condition.Progress;
|
||||
var titleMessage = new FormattedMessage();
|
||||
var descriptionMessage = new FormattedMessage();
|
||||
titleMessage.AddText(condition.Title);
|
||||
descriptionMessage.AddText(condition.Description);
|
||||
titleMessage.TryAddMarkup(condition.Title, out _); //CP14 colored objective text support
|
||||
descriptionMessage.TryAddMarkup(condition.Description, out _); //CP14 colored objective text support
|
||||
|
||||
conditionControl.Title.SetMessage(titleMessage);
|
||||
conditionControl.Description.SetMessage(descriptionMessage);
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
using Content.Shared._CP14.Workbench;
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client._CP14.Workbench;
|
||||
|
||||
public sealed class CP14WorkbenchBoundUserInterface : BoundUserInterface
|
||||
{
|
||||
private CP14WorkbenchWindow? _window;
|
||||
|
||||
public CP14WorkbenchBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void Open()
|
||||
{
|
||||
base.Open();
|
||||
|
||||
_window = this.CreateWindow<CP14WorkbenchWindow>();
|
||||
|
||||
_window.OnCraft += entry => SendMessage(new CP14WorkbenchUiCraftMessage(entry.ProtoId));
|
||||
}
|
||||
|
||||
protected override void UpdateState(BoundUserInterfaceState state)
|
||||
{
|
||||
base.UpdateState(state);
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case CP14WorkbenchUiRecipesState recipesState:
|
||||
_window?.UpdateRecipes(recipesState);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<Control xmlns="https://spacestation14.io">
|
||||
<GridContainer Columns="2">
|
||||
<TextureRect Name="View"
|
||||
Margin="0,0,4,0"
|
||||
MinSize="48 48"
|
||||
HorizontalAlignment="Left"
|
||||
Stretch="KeepAspectCentered"/>
|
||||
<Label Name="Name"/>
|
||||
</GridContainer>
|
||||
</Control>
|
||||
@@ -0,0 +1,45 @@
|
||||
using Content.Shared._CP14.Workbench;
|
||||
using Content.Shared._CP14.Workbench.Prototypes;
|
||||
using Content.Shared.Stacks;
|
||||
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!;
|
||||
|
||||
private readonly SpriteSystem _sprite;
|
||||
|
||||
public CP14WorkbenchRecipeControl()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_sprite = _entity.System<SpriteSystem>();
|
||||
}
|
||||
|
||||
public CP14WorkbenchRecipeControl(EntityPrototype prototype, int count) : this()
|
||||
{
|
||||
var entityName = Loc.GetString(prototype.Name);
|
||||
Name.Text = count <= 1 ? entityName : $"{entityName} x{count}";
|
||||
View.Texture = _sprite.GetPrototypeIcon(prototype).Default;
|
||||
}
|
||||
|
||||
public CP14WorkbenchRecipeControl(StackPrototype prototype, int count) : this()
|
||||
{
|
||||
var entityName = Loc.GetString(prototype.Name);
|
||||
Name.Text = count <= 1 ? entityName : $"{entityName} x{count}";
|
||||
|
||||
var icon = prototype.Icon;
|
||||
if (icon is null)
|
||||
return;
|
||||
|
||||
View.Texture = _sprite.Frame0(icon);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<Control xmlns="https://spacestation14.io">
|
||||
<Button Name="Button">
|
||||
<GridContainer Columns="2">
|
||||
<TextureRect Name="View"
|
||||
Margin="0,0,4,0"
|
||||
MinSize="48 48"
|
||||
HorizontalAlignment="Left"
|
||||
Stretch="KeepAspectCentered"/>
|
||||
<Label Name="Name"/>
|
||||
</GridContainer>
|
||||
</Button>
|
||||
</Control>
|
||||
@@ -0,0 +1,59 @@
|
||||
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 CP14WorkbenchRequirementControl : 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 CP14WorkbenchRequirementControl(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);
|
||||
Name.Text = Loc.GetString(result.Name);
|
||||
}
|
||||
|
||||
private void UpdateView()
|
||||
{
|
||||
View.Texture = _sprite.GetPrototypeIcon(_recipePrototype.Result).Default;
|
||||
}
|
||||
}
|
||||
60
Content.Client/_CP14/Workbench/CP14WorkbenchWindow.xaml
Normal file
60
Content.Client/_CP14/Workbench/CP14WorkbenchWindow.xaml
Normal file
@@ -0,0 +1,60 @@
|
||||
<DefaultWindow xmlns="https://spacestation14.io"
|
||||
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
|
||||
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
|
||||
Title="Workbench"
|
||||
MinSize="700 600">
|
||||
<BoxContainer Orientation="Vertical">
|
||||
<!-- Main -->
|
||||
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Horizontal">
|
||||
<GridContainer HorizontalExpand="True" VerticalExpand="True" Columns="2">
|
||||
<!-- Crafts container -->
|
||||
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" MinSize="0 200">
|
||||
<BoxContainer Name="CraftsContainer" Orientation="Vertical" HorizontalExpand="True"/>
|
||||
</ScrollContainer>
|
||||
|
||||
<!-- Craft view -->
|
||||
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Vertical">
|
||||
<PanelContainer HorizontalExpand="True" VerticalExpand="True">
|
||||
<!-- Background -->
|
||||
<PanelContainer.PanelOverride>
|
||||
<graphics:StyleBoxFlat BackgroundColor="#41332f"/>
|
||||
</PanelContainer.PanelOverride>
|
||||
|
||||
<!-- Content -->
|
||||
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Vertical">
|
||||
<!-- Item info -->
|
||||
<GridContainer HorizontalExpand="True" Columns="2">
|
||||
<!-- Left panel - icon -->
|
||||
<TextureRect Name="ItemView"
|
||||
Margin="0,0,4,0"
|
||||
MinSize="64 64"
|
||||
HorizontalAlignment="Left"
|
||||
Stretch="KeepAspectCentered"/>
|
||||
|
||||
<!-- Right panel - name & description -->
|
||||
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Vertical">
|
||||
<Label Name="ItemName" Text="Name"/>
|
||||
<Label Name="ItemDescription" Text="Description" ClipText="True"/>
|
||||
</BoxContainer>
|
||||
</GridContainer>
|
||||
|
||||
<controls:HLine Color="#404040" Thickness="2" Margin="0 5"/>
|
||||
|
||||
<!-- Required title -->
|
||||
<Label Text="Required"/>
|
||||
|
||||
<!-- Craft requirements content -->
|
||||
<!-- Added by code -->
|
||||
<BoxContainer Name="ItemRequirements" Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True"/>
|
||||
|
||||
<controls:HLine Color="#404040" Thickness="2" Margin="0 5"/>
|
||||
|
||||
<!-- Craft button -->
|
||||
<Button Name="CraftButton" Text="Craft"/>
|
||||
</BoxContainer>
|
||||
</PanelContainer>
|
||||
</BoxContainer>
|
||||
</GridContainer>
|
||||
</BoxContainer>
|
||||
</BoxContainer>
|
||||
</DefaultWindow>
|
||||
92
Content.Client/_CP14/Workbench/CP14WorkbenchWindow.xaml.cs
Normal file
92
Content.Client/_CP14/Workbench/CP14WorkbenchWindow.xaml.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using Content.Shared._CP14.Workbench;
|
||||
using Content.Shared._CP14.Workbench.Prototypes;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Client._CP14.Workbench;
|
||||
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class CP14WorkbenchWindow : DefaultWindow
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entity = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
|
||||
public event Action<CP14WorkbenchUiRecipesEntry>? OnCraft;
|
||||
|
||||
private readonly SpriteSystem _sprite;
|
||||
|
||||
private CP14WorkbenchUiRecipesEntry? _selectedEntry ;
|
||||
|
||||
public CP14WorkbenchWindow()
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
IoCManager.InjectDependencies(this);
|
||||
|
||||
_sprite = _entity.System<SpriteSystem>();
|
||||
|
||||
CraftButton.OnPressed += _ =>
|
||||
{
|
||||
if (_selectedEntry is null)
|
||||
return;
|
||||
|
||||
OnCraft?.Invoke(_selectedEntry.Value);
|
||||
};
|
||||
}
|
||||
|
||||
public void UpdateRecipes(CP14WorkbenchUiRecipesState recipesState)
|
||||
{
|
||||
CraftsContainer.RemoveAllChildren();
|
||||
|
||||
foreach (var entry in recipesState.Recipes)
|
||||
{
|
||||
var control = new CP14WorkbenchRequirementControl(entry);
|
||||
control.OnSelect += RecipeSelect;
|
||||
|
||||
CraftsContainer.AddChild(control);
|
||||
}
|
||||
|
||||
if (_selectedEntry is not null && recipesState.Recipes.Contains(_selectedEntry.Value))
|
||||
{
|
||||
RecipeSelect(_selectedEntry.Value, _prototype.Index(_selectedEntry.Value.ProtoId));
|
||||
return;
|
||||
}
|
||||
|
||||
RecipeSelect(recipesState);
|
||||
}
|
||||
|
||||
private void RecipeSelect(CP14WorkbenchUiRecipesState recipesState)
|
||||
{
|
||||
foreach (var entry in recipesState.Recipes)
|
||||
{
|
||||
RecipeSelect(entry, _prototype.Index(entry.ProtoId));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void RecipeSelect(CP14WorkbenchUiRecipesEntry entry, CP14WorkbenchRecipePrototype recipe)
|
||||
{
|
||||
_selectedEntry = entry;
|
||||
|
||||
var result = _prototype.Index(recipe.Result);
|
||||
|
||||
ItemView.Texture = _sprite.GetPrototypeIcon(recipe.Result).Default;
|
||||
ItemName.Text = Loc.GetString(result.Name);
|
||||
ItemDescription.Text = Loc.GetString(result.Description);
|
||||
|
||||
ItemRequirements.RemoveAllChildren();
|
||||
foreach (var (entProtoId, count) in recipe.Entities)
|
||||
{
|
||||
ItemRequirements.AddChild(new CP14WorkbenchRecipeControl(_prototype.Index(entProtoId), count));
|
||||
}
|
||||
|
||||
foreach (var (entProtoId, count) in recipe.Stacks)
|
||||
{
|
||||
ItemRequirements.AddChild(new CP14WorkbenchRecipeControl(_prototype.Index(entProtoId), count));
|
||||
}
|
||||
|
||||
CraftButton.Disabled = !entry.Craftable;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#nullable enable
|
||||
#nullable enable
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.GameTicking.Presets;
|
||||
using Content.Shared.CCVar;
|
||||
@@ -36,7 +36,7 @@ public sealed class FailAndStartPresetTest
|
||||
- type: entity
|
||||
id: TestRule
|
||||
parent: BaseGameRule
|
||||
noSpawn: true
|
||||
categories: [ GameRules ]
|
||||
components:
|
||||
- type: GameRule
|
||||
minPlayers: 0
|
||||
@@ -45,7 +45,7 @@ public sealed class FailAndStartPresetTest
|
||||
- type: entity
|
||||
id: TestRuleTenPlayers
|
||||
parent: BaseGameRule
|
||||
noSpawn: true
|
||||
categories: [ GameRules ]
|
||||
components:
|
||||
- type: GameRule
|
||||
minPlayers: 10
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace Content.IntegrationTests.Tests.GameRules;
|
||||
|
||||
[TestFixture]
|
||||
public sealed class NukeOpsTest
|
||||
{
|
||||
{/*
|
||||
/// <summary>
|
||||
/// Check that a nuke ops game mode can start without issue. I.e., that the nuke station and such all get loaded.
|
||||
/// </summary>
|
||||
@@ -250,5 +250,5 @@ public sealed class NukeOpsTest
|
||||
|
||||
ticker.SetGamePreset((GamePresetPrototype?) null);
|
||||
await pair.CleanReturnAsync();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -43,31 +43,16 @@ namespace Content.IntegrationTests.Tests
|
||||
};
|
||||
|
||||
private static readonly string[] GameMaps =
|
||||
{
|
||||
"Dev", //CrystallPunk Map replacement
|
||||
//"TestTeg",
|
||||
//"Fland",
|
||||
//"Meta",
|
||||
//"Packed",
|
||||
//"Cluster",
|
||||
//"Omega",
|
||||
//"Bagel",
|
||||
//"Origin",
|
||||
{//CrystallPunk Map replacement
|
||||
"Dev",
|
||||
"CentComm",
|
||||
//"Box",
|
||||
//"Europa",
|
||||
//"Saltern",
|
||||
//"Core",
|
||||
//"Marathon",
|
||||
"MeteorArena",
|
||||
//"Atlas",
|
||||
//"Reach",
|
||||
//"Train",
|
||||
//"Oasis"
|
||||
|
||||
//CrystallPunk maps
|
||||
"AlchemyTest",
|
||||
"BattleRoyale"
|
||||
"BattleRoyale",
|
||||
"ExpeditionTest",
|
||||
//CrystallPunk Map replacement end
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -212,10 +197,10 @@ namespace Content.IntegrationTests.Tests
|
||||
targetGrid = gridEnt;
|
||||
}
|
||||
}
|
||||
|
||||
// Test shuttle can dock.
|
||||
// This is done inside gamemap test because loading the map takes ages and we already have it.
|
||||
var station = entManager.GetComponent<StationMemberComponent>(targetGrid!.Value).Station;
|
||||
/*
|
||||
if (entManager.TryGetComponent<StationEmergencyShuttleComponent>(station, out var stationEvac))
|
||||
{
|
||||
var shuttlePath = stationEvac.EmergencyShuttlePath;
|
||||
@@ -234,7 +219,7 @@ namespace Content.IntegrationTests.Tests
|
||||
}
|
||||
|
||||
mapManager.DeleteMap(shuttleMap);
|
||||
|
||||
*/ //CP14 Disable FTL test
|
||||
if (entManager.HasComponent<StationJobsComponent>(station))
|
||||
{
|
||||
// Test that the map has valid latejoin spawn points or container spawn points
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace Content.IntegrationTests.Tests.Station;
|
||||
[TestFixture]
|
||||
[TestOf(typeof(EmergencyShuttleSystem))]
|
||||
public sealed class EvacShuttleTest
|
||||
{
|
||||
{/*
|
||||
/// <summary>
|
||||
/// Ensure that the emergency shuttle can be called, and that it will travel to centcomm
|
||||
/// </summary>
|
||||
@@ -123,5 +123,5 @@ public sealed class EvacShuttleTest
|
||||
pair.Server.CfgMan.SetCVar(CCVars.EmergencyShuttleEnabled, false);
|
||||
pair.Server.CfgMan.SetCVar(CCVars.GameMap, gameMap);
|
||||
await pair.CleanReturnAsync();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public sealed class JobWhitelistAddCommand : LocalizedCommands
|
||||
var isWhitelisted = await _db.IsJobWhitelisted(guid, job);
|
||||
if (isWhitelisted)
|
||||
{
|
||||
shell.WriteLine(Loc.GetString("cmd-jobwhitelist-already-whitelisted",
|
||||
shell.WriteLine(Loc.GetString("cmd-jobwhitelistadd-already-whitelisted",
|
||||
("player", player),
|
||||
("jobId", job.Id),
|
||||
("jobName", jobPrototype.LocalizedName)));
|
||||
|
||||
@@ -285,18 +285,18 @@ public sealed partial class AdminVerbSystem
|
||||
{
|
||||
Text = "admin-smite-remove-hands-name",
|
||||
Category = VerbCategory.Smite,
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Fluids/vomit_toxin.rsi"), "vomit_toxin-1"),
|
||||
Icon = new SpriteSpecifier.Rsi(new("/Textures/Fluids/vomit_toxin.rsi"), "vomit_toxin-1"),
|
||||
Act = () =>
|
||||
{
|
||||
_vomitSystem.Vomit(args.Target, -1000, -1000); // You feel hollow!
|
||||
var organs = _bodySystem.GetBodyOrganComponents<TransformComponent>(args.Target, body);
|
||||
var organs = _bodySystem.GetBodyOrganEntityComps<TransformComponent>((args.Target, body));
|
||||
var baseXform = Transform(args.Target);
|
||||
foreach (var (xform, organ) in organs)
|
||||
foreach (var organ in organs)
|
||||
{
|
||||
if (HasComp<BrainComponent>(xform.Owner) || HasComp<EyeComponent>(xform.Owner))
|
||||
if (HasComp<BrainComponent>(organ.Owner) || HasComp<EyeComponent>(organ.Owner))
|
||||
continue;
|
||||
|
||||
_transformSystem.AttachToGridOrMap(organ.Owner);
|
||||
_transformSystem.PlaceNextTo((organ.Owner, organ.Comp1), (args.Target, baseXform));
|
||||
}
|
||||
|
||||
_popupSystem.PopupEntity(Loc.GetString("admin-smite-vomit-organs-self"), args.Target,
|
||||
@@ -361,9 +361,9 @@ public sealed partial class AdminVerbSystem
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Mobs/Species/Human/organs.rsi"), "stomach"),
|
||||
Act = () =>
|
||||
{
|
||||
foreach (var (component, _) in _bodySystem.GetBodyOrganComponents<StomachComponent>(args.Target, body))
|
||||
foreach (var entity in _bodySystem.GetBodyOrganEntityComps<StomachComponent>((args.Target, body)))
|
||||
{
|
||||
QueueDel(component.Owner);
|
||||
QueueDel(entity.Owner);
|
||||
}
|
||||
|
||||
_popupSystem.PopupEntity(Loc.GetString("admin-smite-stomach-removal-self"), args.Target,
|
||||
@@ -381,9 +381,9 @@ public sealed partial class AdminVerbSystem
|
||||
Icon = new SpriteSpecifier.Rsi(new ("/Textures/Mobs/Species/Human/organs.rsi"), "lung-r"),
|
||||
Act = () =>
|
||||
{
|
||||
foreach (var (component, _) in _bodySystem.GetBodyOrganComponents<LungComponent>(args.Target, body))
|
||||
foreach (var entity in _bodySystem.GetBodyOrganEntityComps<LungComponent>((args.Target, body)))
|
||||
{
|
||||
QueueDel(component.Owner);
|
||||
QueueDel(entity.Owner);
|
||||
}
|
||||
|
||||
_popupSystem.PopupEntity(Loc.GetString("admin-smite-lung-removal-self"), args.Target,
|
||||
|
||||
@@ -122,7 +122,7 @@ public sealed partial class AnomalySynchronizerSystem : EntitySystem
|
||||
_audio.PlayPvs(ent.Comp.ConnectedSound, ent);
|
||||
}
|
||||
|
||||
//TO DO: disconnection from the anomaly should also be triggered if the anomaly is far away from the synchronizer.
|
||||
//TODO: disconnection from the anomaly should also be triggered if the anomaly is far away from the synchronizer.
|
||||
//Currently only bluespace anomaly can do this, but for some reason it is the only one that cannot be connected to the synchronizer.
|
||||
private void DisconneсtFromAnomaly(Entity<AnomalySynchronizerComponent> ent, AnomalyComponent anomaly)
|
||||
{
|
||||
|
||||
@@ -76,7 +76,7 @@ public sealed class ReagentProducerAnomalySystem : EntitySystem
|
||||
if (anomaly.Severity >= 0.97) reagentProducingAmount *= component.SupercriticalReagentProducingModifier;
|
||||
|
||||
newSol.AddReagent(component.ProducingReagent, reagentProducingAmount);
|
||||
_solutionContainer.TryAddSolution(component.Solution.Value, newSol); //TO DO - the container is not fully filled.
|
||||
_solutionContainer.TryAddSolution(component.Solution.Value, newSol); // TODO - the container is not fully filled.
|
||||
|
||||
component.AccumulatedFrametime = 0;
|
||||
|
||||
|
||||
@@ -336,7 +336,7 @@ public sealed partial class AntagSelectionSystem : GameRuleSystem<AntagSelection
|
||||
}
|
||||
|
||||
_mind.TransferTo(curMind.Value, antagEnt, ghostCheckOverride: true);
|
||||
_role.MindAddRoles(curMind.Value, def.MindComponents);
|
||||
_role.MindAddRoles(curMind.Value, def.MindComponents, null, true);
|
||||
ent.Comp.SelectedMinds.Add((curMind.Value, Name(player)));
|
||||
SendBriefing(session, def.Briefing);
|
||||
}
|
||||
|
||||
@@ -157,7 +157,7 @@ public sealed partial class BlockGame
|
||||
/// <param name="message">The message to broadcase to all players/spectators.</param>
|
||||
private void SendMessage(BoundUserInterfaceMessage message)
|
||||
{
|
||||
_uiSystem.ServerSendUiMessage(_entityManager.GetEntity(message.Entity), BlockGameUiKey.Key, message);
|
||||
_uiSystem.ServerSendUiMessage(_owner, BlockGameUiKey.Key, message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -167,7 +167,7 @@ public sealed partial class BlockGame
|
||||
/// <param name="actor">The target recipient.</param>
|
||||
private void SendMessage(BoundUserInterfaceMessage message, EntityUid actor)
|
||||
{
|
||||
_uiSystem.ServerSendUiMessage(_entityManager.GetEntity(message.Entity), BlockGameUiKey.Key, message, actor);
|
||||
_uiSystem.ServerSendUiMessage(_owner, BlockGameUiKey.Key, message, actor);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -31,7 +31,7 @@ public sealed class CharacterInfoSystem : EntitySystem
|
||||
var entity = args.SenderSession.AttachedEntity.Value;
|
||||
|
||||
var objectives = new Dictionary<string, List<ObjectiveInfo>>();
|
||||
var jobTitle = "No Profession";
|
||||
var jobTitle = Loc.GetString("character-info-no-profession");
|
||||
string? briefing = null;
|
||||
if (_minds.TryGetMind(entity, out var mindId, out var mind))
|
||||
{
|
||||
|
||||
@@ -206,9 +206,9 @@ public sealed class InjectorSystem : SharedInjectorSystem
|
||||
BreakOnMove = true,
|
||||
BreakOnWeightlessMove = false,
|
||||
BreakOnDamage = true,
|
||||
NeedHand = true,
|
||||
BreakOnHandChange = true,
|
||||
MovementThreshold = 0.1f,
|
||||
NeedHand = injector.Comp.NeedHand,
|
||||
BreakOnHandChange = injector.Comp.BreakOnHandChange,
|
||||
MovementThreshold = injector.Comp.MovementThreshold,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using Content.Server._CP14.MeleeWeapon;
|
||||
using Content.Server._CP14.MeleeWeapon.Components;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Damage.Components;
|
||||
using Content.Server.Weapons.Ranged.Systems;
|
||||
using Content.Shared._CP14.MeleeWeapon.Components;
|
||||
using Content.Shared.Camera;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Damage.Events;
|
||||
@@ -43,7 +42,7 @@ namespace Content.Server.Damage.Systems
|
||||
damage *= sharp.Sharpness;
|
||||
|
||||
var dmg = _damageable.TryChangeDamage(args.Target, damage, component.IgnoreResistances, origin: args.Component.Thrower);
|
||||
//CrystallPunk Melee pgrade end
|
||||
//CrystallPunk Melee upgrade end
|
||||
|
||||
// Log damage only for mobs. Useful for when people throw spears at each other, but also avoids log-spam when explosions send glass shards flying.
|
||||
if (dmg != null && HasComp<MobStateComponent>(args.Target))
|
||||
|
||||
@@ -16,7 +16,7 @@ public sealed class DamagedByFlashingSystem : EntitySystem
|
||||
{
|
||||
_damageable.TryChangeDamage(ent, ent.Comp.FlashDamage);
|
||||
|
||||
//To Do: It would be more logical if different flashes had different power,
|
||||
//TODO: It would be more logical if different flashes had different power,
|
||||
//and the damage would be inflicted depending on the strength of the flash.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +96,7 @@ public sealed class ToggleableGhostRoleSystem : EntitySystem
|
||||
|
||||
private void AddWipeVerb(EntityUid uid, ToggleableGhostRoleComponent component, GetVerbsEvent<ActivationVerb> args)
|
||||
{
|
||||
if (!args.CanAccess || !args.CanInteract)
|
||||
if (args.Hands == null || !args.CanAccess || !args.CanInteract)
|
||||
return;
|
||||
|
||||
if (TryComp<MindContainerComponent>(uid, out var mind) && mind.HasMind)
|
||||
|
||||
@@ -157,7 +157,7 @@ namespace Content.Server.Kitchen.EntitySystems
|
||||
var outputContainer = _itemSlotsSystem.GetItemOrNull(uid, SharedReagentGrinder.BeakerSlotId);
|
||||
_appearanceSystem.SetData(uid, ReagentGrinderVisualState.BeakerAttached, outputContainer.HasValue);
|
||||
|
||||
if (reagentGrinder.AutoMode != GrinderAutoMode.Off && !HasComp<ActiveReagentGrinderComponent>(uid))
|
||||
if (reagentGrinder.AutoMode != GrinderAutoMode.Off && !HasComp<ActiveReagentGrinderComponent>(uid) && this.IsPowered(uid, EntityManager))
|
||||
{
|
||||
var program = reagentGrinder.AutoMode == GrinderAutoMode.Grind ? GrinderProgram.Grind : GrinderProgram.Juice;
|
||||
DoWork(uid, reagentGrinder, program);
|
||||
|
||||
@@ -71,9 +71,9 @@ public sealed class LightningSystem : SharedLightningSystem
|
||||
/// <param name="triggerLightningEvents">if the lightnings being fired should trigger lightning events.</param>
|
||||
public void ShootRandomLightnings(EntityUid user, float range, int boltCount, string lightningPrototype = "Lightning", int arcDepth = 0, bool triggerLightningEvents = true)
|
||||
{
|
||||
//To Do: add support to different priority target tablem for different lightning types
|
||||
//To Do: Remove Hardcode LightningTargetComponent (this should be a parameter of the SharedLightningComponent)
|
||||
//To Do: This is still pretty bad for perf but better than before and at least it doesn't re-allocate
|
||||
//TODO: add support to different priority target tablem for different lightning types
|
||||
//TODO: Remove Hardcode LightningTargetComponent (this should be a parameter of the SharedLightningComponent)
|
||||
//TODO: This is still pretty bad for perf but better than before and at least it doesn't re-allocate
|
||||
// several hashsets every time
|
||||
|
||||
var targets = _lookup.GetComponentsInRange<LightningTargetComponent>(_transform.GetMapCoordinates(user), range).ToList();
|
||||
|
||||
@@ -26,6 +26,11 @@ public interface IGridSpawnGroup
|
||||
/// </summary>
|
||||
public float MinimumDistance { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Maximum distance to spawn away from the station.
|
||||
/// </summary>
|
||||
public float MaximumDistance { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ProtoId<DatasetPrototype>? NameDataset { get; }
|
||||
|
||||
@@ -67,6 +72,8 @@ public sealed class DungeonSpawnGroup : IGridSpawnGroup
|
||||
/// <inheritdoc />
|
||||
public float MinimumDistance { get; }
|
||||
|
||||
public float MaximumDistance { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public ProtoId<DatasetPrototype>? NameDataset { get; }
|
||||
|
||||
@@ -94,7 +101,11 @@ public sealed class GridSpawnGroup : IGridSpawnGroup
|
||||
{
|
||||
public List<ResPath> Paths = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public float MinimumDistance { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public float MaximumDistance { get; }
|
||||
public ProtoId<DatasetPrototype>? NameDataset { get; }
|
||||
public int MinCount { get; set; } = 1;
|
||||
public int MaxCount { get; set; } = 1;
|
||||
|
||||
@@ -281,24 +281,24 @@ namespace Content.Server.Shuttles.Systems
|
||||
{
|
||||
if (_doorSystem.TryOpen(dockAUid, doorA))
|
||||
{
|
||||
doorA.ChangeAirtight = false;
|
||||
if (TryComp<DoorBoltComponent>(dockAUid, out var airlockA))
|
||||
{
|
||||
_doorSystem.SetBoltsDown((dockAUid, airlockA), true);
|
||||
}
|
||||
}
|
||||
doorA.ChangeAirtight = false;
|
||||
}
|
||||
|
||||
if (TryComp(dockBUid, out DoorComponent? doorB))
|
||||
{
|
||||
if (_doorSystem.TryOpen(dockBUid, doorB))
|
||||
{
|
||||
doorB.ChangeAirtight = false;
|
||||
if (TryComp<DoorBoltComponent>(dockBUid, out var airlockB))
|
||||
{
|
||||
_doorSystem.SetBoltsDown((dockBUid, airlockB), true);
|
||||
}
|
||||
}
|
||||
doorB.ChangeAirtight = false;
|
||||
}
|
||||
|
||||
if (_pathfinding.TryCreatePortal(dockAXform.Coordinates, dockBXform.Coordinates, out var handle))
|
||||
|
||||
@@ -10,6 +10,7 @@ using Content.Shared.Shuttles.Components;
|
||||
using Content.Shared.Station.Components;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -86,9 +87,15 @@ public sealed partial class ShuttleSystem
|
||||
_mapManager.DeleteMap(mapId);
|
||||
}
|
||||
|
||||
private bool TryDungeonSpawn(EntityUid targetGrid, EntityUid stationUid, MapId mapId, DungeonSpawnGroup group, out EntityUid spawned)
|
||||
private bool TryDungeonSpawn(Entity<MapGridComponent?> targetGrid, EntityUid stationUid, MapId mapId, DungeonSpawnGroup group, out EntityUid spawned)
|
||||
{
|
||||
spawned = EntityUid.Invalid;
|
||||
|
||||
if (!_gridQuery.Resolve(targetGrid.Owner, ref targetGrid.Comp))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var dungeonProtoId = _random.Pick(group.Protos);
|
||||
|
||||
if (!_protoManager.TryIndex(dungeonProtoId, out var dungeonProto))
|
||||
@@ -96,11 +103,13 @@ public sealed partial class ShuttleSystem
|
||||
return false;
|
||||
}
|
||||
|
||||
var spawnCoords = new EntityCoordinates(targetGrid, Vector2.Zero);
|
||||
var targetPhysics = _physicsQuery.Comp(targetGrid);
|
||||
var spawnCoords = new EntityCoordinates(targetGrid, targetPhysics.LocalCenter);
|
||||
|
||||
if (group.MinimumDistance > 0f)
|
||||
{
|
||||
spawnCoords = spawnCoords.Offset(_random.NextVector2(group.MinimumDistance, group.MinimumDistance * 1.5f));
|
||||
var distancePadding = MathF.Max(targetGrid.Comp.LocalAABB.Width, targetGrid.Comp.LocalAABB.Height);
|
||||
spawnCoords = spawnCoords.Offset(_random.NextVector2(distancePadding + group.MinimumDistance, distancePadding + group.MaximumDistance));
|
||||
}
|
||||
|
||||
var spawnMapCoords = _transform.ToMapCoordinates(spawnCoords);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.Shuttles.Components;
|
||||
using Content.Shared.CCVar;
|
||||
using Content.Shared.Shuttles.BUIStates;
|
||||
using Content.Shared.Shuttles.Components;
|
||||
using Content.Shared.Shuttles.Events;
|
||||
@@ -12,6 +13,26 @@ public sealed partial class ShuttleSystem
|
||||
SubscribeLocalEvent<IFFConsoleComponent, AnchorStateChangedEvent>(OnIFFConsoleAnchor);
|
||||
SubscribeLocalEvent<IFFConsoleComponent, IFFShowIFFMessage>(OnIFFShow);
|
||||
SubscribeLocalEvent<IFFConsoleComponent, IFFShowVesselMessage>(OnIFFShowVessel);
|
||||
SubscribeLocalEvent<GridSplitEvent>(OnGridSplit);
|
||||
}
|
||||
|
||||
private void OnGridSplit(ref GridSplitEvent ev)
|
||||
{
|
||||
var splitMass = _cfg.GetCVar(CCVars.HideSplitGridsUnder);
|
||||
|
||||
if (splitMass < 0)
|
||||
return;
|
||||
|
||||
foreach (var grid in ev.NewGrids)
|
||||
{
|
||||
if (!_physicsQuery.TryGetComponent(grid, out var physics) ||
|
||||
physics.Mass > splitMass)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
AddIFFFlag(grid, IFFFlags.HideLabel);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnIFFShow(EntityUid uid, IFFConsoleComponent component, IFFShowIFFMessage args)
|
||||
|
||||
@@ -60,12 +60,16 @@ public sealed partial class ShuttleSystem : SharedShuttleSystem
|
||||
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
|
||||
[Dependency] private readonly AtmosphereSystem _atmos = default!; //CP14 FTL atmos
|
||||
|
||||
private EntityQuery<MapGridComponent> _gridQuery;
|
||||
|
||||
public const float TileMassMultiplier = 0.5f;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_gridQuery = GetEntityQuery<MapGridComponent>();
|
||||
|
||||
InitializeFTL();
|
||||
InitializeGridFills();
|
||||
InitializeIFF();
|
||||
|
||||
@@ -68,6 +68,8 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
|
||||
_spawnerCallbacks = new Dictionary<SpawnPriorityPreference, Action<PlayerSpawningEvent>>()
|
||||
{
|
||||
{ SpawnPriorityPreference.Arrivals, _CP14expedition.HandlePlayerSpawning }, //CP14 expedition system replaced
|
||||
{ SpawnPriorityPreference.Cryosleep, _CP14expedition.HandlePlayerSpawning }, //CP14 expedition system replaced
|
||||
/*
|
||||
{
|
||||
SpawnPriorityPreference.Cryosleep, ev =>
|
||||
{
|
||||
@@ -76,7 +78,7 @@ public sealed class StationSpawningSystem : SharedStationSpawningSystem
|
||||
else
|
||||
_containerSpawnPointSystem.HandlePlayerSpawning(ev);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* All right reserved to CrystallPunk.
|
||||
*
|
||||
* This file is sublicensed under Custom License Agreement for Stalker14 project (https://github.com/stalker14-project/stalker14) only
|
||||
*
|
||||
* See LICENSE.TXT file in the project root for full license information.
|
||||
* Copyright (c) 2024 TheShuEd (Github)
|
||||
*/
|
||||
|
||||
using System.Numerics;
|
||||
using Content.Server.Decals;
|
||||
using Content.Server.GameTicking;
|
||||
using Content.Server.Parallax;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._CP14.BiomeSpawner;
|
||||
|
||||
public sealed class CP14BiomeSpawnerSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly BiomeSystem _biome = default!;
|
||||
[Dependency] private readonly TransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedMapSystem _maps = default!;
|
||||
[Dependency] private readonly DecalSystem _decals = default!;
|
||||
[Dependency] private readonly IEntityManager _entManager = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
private int _seed = 27;
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<RoundStartAttemptEvent>(OnRoundStartAttempt);
|
||||
SubscribeLocalEvent<CP14BiomeSpawnerComponent, MapInitEvent>(OnMapInit);
|
||||
}
|
||||
|
||||
private void OnRoundStartAttempt(RoundStartAttemptEvent ev)
|
||||
{
|
||||
_seed = _random.Next(100000);
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<CP14BiomeSpawnerComponent> spawner, ref MapInitEvent args)
|
||||
{
|
||||
SpawnBiome(spawner);
|
||||
QueueDel(spawner);
|
||||
}
|
||||
|
||||
private void SpawnBiome(Entity<CP14BiomeSpawnerComponent> spawner)
|
||||
{
|
||||
var biome = _proto.Index(spawner.Comp.Biome);
|
||||
var parent = _transform.GetParent(spawner);
|
||||
|
||||
if (parent == null)
|
||||
return;
|
||||
|
||||
var gridUid = parent.Owner;
|
||||
|
||||
if (!TryComp<MapGridComponent>(gridUid, out var map))
|
||||
return;
|
||||
|
||||
var v2i = _transform.GetGridOrMapTilePosition(spawner);
|
||||
if (!_biome.TryGetTile(v2i, biome.Layers, _seed, map, out var tile))
|
||||
return;
|
||||
|
||||
// Set new tile
|
||||
_maps.SetTile(gridUid, map, v2i, tile.Value);
|
||||
|
||||
// Remove old decals
|
||||
var oldDecals = _decals.GetDecalsInRange(gridUid, v2i + new Vector2(0.5f, 0.5f));
|
||||
foreach (var (id, _) in oldDecals)
|
||||
{
|
||||
_decals.RemoveDecal(gridUid, id);
|
||||
}
|
||||
|
||||
//Add decals
|
||||
if (_biome.TryGetDecals(v2i, biome.Layers, _seed, map, out var decals))
|
||||
{
|
||||
foreach (var decal in decals)
|
||||
{
|
||||
_decals.TryAddDecal(decal.ID, new EntityCoordinates(gridUid, decal.Position), out _);
|
||||
}
|
||||
}
|
||||
|
||||
//TODO maybe need remove anchored entities here
|
||||
|
||||
//Add entities
|
||||
if (_biome.TryGetEntity(v2i, biome.Layers, tile.Value, _seed, map, out var entityProto))
|
||||
{
|
||||
var ent = _entManager.SpawnEntity(entityProto,
|
||||
new EntityCoordinates(gridUid, v2i + map.TileSizeHalfVector));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,15 @@
|
||||
/*
|
||||
* All right reserved to CrystallPunk.
|
||||
*
|
||||
* This file is sublicensed under Custom License Agreement for Stalker14 project (https://github.com/stalker14-project/stalker14) only
|
||||
* BUT this file is sublicensed under MIT License
|
||||
*
|
||||
* See LICENSE.TXT file in the project root for full license information.
|
||||
* Copyright (c) 2024 TheShuEd (Github)
|
||||
*/
|
||||
|
||||
using Content.Server._CP14.BiomeSpawner.EntitySystems;
|
||||
using Content.Shared.Parallax.Biomes;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.BiomeSpawner;
|
||||
namespace Content.Server._CP14.BiomeSpawner.Components;
|
||||
|
||||
/// <summary>
|
||||
/// fills the tile in which it is located with the contents of the biome. Includes: tile, decals and entities
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* All right reserved to CrystallPunk.
|
||||
*
|
||||
* BUT this file is sublicensed under MIT License
|
||||
*
|
||||
*/
|
||||
|
||||
using System.Linq;
|
||||
using Content.Server._CP14.BiomeSpawner.Components;
|
||||
using Content.Server._CP14.RoundSeed;
|
||||
using Content.Server.Decals;
|
||||
using Content.Server.Parallax;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.BiomeSpawner.EntitySystems;
|
||||
|
||||
public sealed class CP14BiomeSpawnerSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly BiomeSystem _biome = default!;
|
||||
[Dependency] private readonly TransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedMapSystem _maps = default!;
|
||||
[Dependency] private readonly DecalSystem _decals = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly CP14RoundSeedSystem _roundSeed = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<CP14BiomeSpawnerComponent, MapInitEvent>(OnMapInit);
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<CP14BiomeSpawnerComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
SpawnBiome(ent);
|
||||
QueueDel(ent);
|
||||
}
|
||||
|
||||
private void SpawnBiome(Entity<CP14BiomeSpawnerComponent> ent)
|
||||
{
|
||||
var biome = _proto.Index(ent.Comp.Biome);
|
||||
var spawnerTransform = Transform(ent);
|
||||
if (spawnerTransform.GridUid == null)
|
||||
return;
|
||||
|
||||
var gridUid = spawnerTransform.GridUid.Value;
|
||||
|
||||
if (!TryComp<MapGridComponent>(gridUid, out var map))
|
||||
return;
|
||||
|
||||
var seed = _roundSeed.GetSeed();
|
||||
|
||||
var vec = _transform.GetGridOrMapTilePosition(ent);
|
||||
|
||||
if (!_biome.TryGetTile(vec, biome.Layers, seed, map, out var tile))
|
||||
return;
|
||||
|
||||
// Set new tile
|
||||
_maps.SetTile(gridUid, map, vec, tile.Value);
|
||||
|
||||
var tileCenterVec = vec + map.TileSizeHalfVector;
|
||||
|
||||
// Remove old decals
|
||||
var oldDecals = _decals.GetDecalsInRange(gridUid, tileCenterVec);
|
||||
foreach (var (id, _) in oldDecals)
|
||||
{
|
||||
_decals.RemoveDecal(gridUid, id);
|
||||
}
|
||||
|
||||
//Add decals
|
||||
if (_biome.TryGetDecals(vec, biome.Layers, seed, map, out var decals))
|
||||
{
|
||||
foreach (var decal in decals)
|
||||
{
|
||||
_decals.TryAddDecal(decal.ID, new EntityCoordinates(gridUid, decal.Position), out _);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove entities
|
||||
var oldEntities = _lookup.GetEntitiesInRange(spawnerTransform.Coordinates, 0.48f);
|
||||
// TODO: Replace this shit with GetEntitiesInBox2
|
||||
foreach (var entToRemove in oldEntities.Concat(new[] { ent.Owner })) // Do not remove self
|
||||
{
|
||||
QueueDel(entToRemove);
|
||||
}
|
||||
|
||||
if (_biome.TryGetEntity(vec, biome.Layers, tile.Value, seed, map, out var entityProto))
|
||||
Spawn(entityProto, new EntityCoordinates(gridUid, tileCenterVec));
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,16 @@
|
||||
using Content.Server._CP14.GameTicking.Rules.Components;
|
||||
using Content.Server.Mind;
|
||||
using Content.Shared.Random.Helpers;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server.GameTicking.Rules;
|
||||
|
||||
public sealed class CP14ExpeditionObjectivesRule : GameRuleSystem<CP14ExpeditionObjectivesRuleComponent>
|
||||
{
|
||||
[Dependency] private readonly MindSystem _mind = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -25,9 +30,38 @@ public sealed class CP14ExpeditionObjectivesRule : GameRuleSystem<CP14Expedition
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var objective in expedition.Objectives)
|
||||
foreach (var (job, groups) in expedition.RoleObjectives)
|
||||
{
|
||||
_mind.TryAddObjective(mindId.Value, mind, objective);
|
||||
if (args.JobId is null || args.JobId != job)
|
||||
continue;
|
||||
|
||||
foreach (var weightGroupProto in groups)
|
||||
{
|
||||
if (!_proto.TryIndex(weightGroupProto, out var weightGroup))
|
||||
continue;
|
||||
|
||||
_mind.TryAddObjective(mindId.Value, mind, weightGroup.Pick(_random));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var (departmentProto, objectives) in expedition.DepartmentObjectives)
|
||||
{
|
||||
if (args.JobId is null)
|
||||
continue;
|
||||
|
||||
if (!_proto.TryIndex(departmentProto, out var department))
|
||||
continue;
|
||||
|
||||
if (!department.Roles.Contains(args.JobId))
|
||||
continue;
|
||||
|
||||
foreach (var weightGroupProto in objectives)
|
||||
{
|
||||
if (!_proto.TryIndex(weightGroupProto, out var weightGroup))
|
||||
continue;
|
||||
|
||||
_mind.TryAddObjective(mindId.Value, mind, weightGroup.Pick(_random));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
using Content.Server.GameTicking.Rules;
|
||||
using Content.Shared.Random;
|
||||
using Content.Shared.Roles;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.GameTicking.Rules.Components;
|
||||
@@ -10,5 +12,8 @@ namespace Content.Server._CP14.GameTicking.Rules.Components;
|
||||
public sealed partial class CP14ExpeditionObjectivesRuleComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public List<EntProtoId> Objectives = new();
|
||||
public Dictionary<ProtoId<JobPrototype>, List<ProtoId<WeightedRandomPrototype>>> RoleObjectives = new();
|
||||
|
||||
[DataField]
|
||||
public Dictionary<ProtoId<DepartmentPrototype>, List<ProtoId<WeightedRandomPrototype>>> DepartmentObjectives = new();
|
||||
}
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
using System.Linq;
|
||||
using Content.Server.GameTicking.Events;
|
||||
using Content.Shared._CP14.LockKey;
|
||||
using Content.Shared.Containers.ItemSlots;
|
||||
using Content.Shared._CP14.LockKey.Components;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Lock;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.GameTicking;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using CP14KeyComponent = Content.Shared._CP14.LockKey.Components.CP14KeyComponent;
|
||||
using CP14LockComponent = Content.Shared._CP14.LockKey.Components.CP14LockComponent;
|
||||
|
||||
namespace Content.Server._CP14.LockKey;
|
||||
|
||||
@@ -16,9 +12,6 @@ public sealed partial class CP14KeyholeGenerationSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly ItemSlotsSystem _itemSlots = default!;
|
||||
[Dependency] private readonly LockSystem _lock = default!;
|
||||
|
||||
private Dictionary<ProtoId<CP14LockCategoryPrototype>, List<int>> _roundKeyData = new();
|
||||
|
||||
@@ -28,7 +21,7 @@ public sealed partial class CP14KeyholeGenerationSystem : EntitySystem
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<RoundStartingEvent>(OnRoundStart);
|
||||
SubscribeLocalEvent<RoundRestartCleanupEvent>(OnRoundEnd);
|
||||
|
||||
SubscribeLocalEvent<CP14LockComponent, MapInitEvent>(OnLockInit);
|
||||
SubscribeLocalEvent<CP14KeyComponent, MapInitEvent>(OnKeyInit);
|
||||
@@ -37,7 +30,7 @@ public sealed partial class CP14KeyholeGenerationSystem : EntitySystem
|
||||
}
|
||||
|
||||
#region Init
|
||||
private void OnRoundStart(RoundStartingEvent ev)
|
||||
private void OnRoundEnd(RoundRestartCleanupEvent ev)
|
||||
{
|
||||
_roundKeyData = new();
|
||||
}
|
||||
@@ -68,7 +61,7 @@ public sealed partial class CP14KeyholeGenerationSystem : EntitySystem
|
||||
if (key.Comp.LockShape == null)
|
||||
return;
|
||||
|
||||
var markup = Loc.GetString("cp-lock-examine-key", ("item", MetaData(key).EntityName));
|
||||
var markup = Loc.GetString("cp14-lock-examine-key", ("item", MetaData(key).EntityName));
|
||||
markup += " (";
|
||||
foreach (var item in key.Comp.LockShape)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
using System.Numerics;
|
||||
using Content.Server._CP14.MagicEnergy.Components;
|
||||
using Content.Shared._CP14.MagicEnergy.Components;
|
||||
|
||||
namespace Content.Server._CP14.MagicEnergy;
|
||||
|
||||
public partial class CP14MagicEnergySystem
|
||||
{
|
||||
private void InitializeDraw()
|
||||
{
|
||||
SubscribeLocalEvent<CP14MagicEnergyDrawComponent, MapInitEvent>(OnDrawMapInit);
|
||||
SubscribeLocalEvent<CP14RandomAuraNodeComponent, MapInitEvent>(OnRandomRangeMapInit);
|
||||
}
|
||||
|
||||
private void OnRandomRangeMapInit(Entity<CP14RandomAuraNodeComponent> random, ref MapInitEvent args)
|
||||
{
|
||||
if (!TryComp<CP14AuraNodeComponent>(random, out var draw))
|
||||
return;
|
||||
|
||||
draw.Energy = _random.NextFloat(random.Comp.MinDraw, random.Comp.MaxDraw);
|
||||
draw.Range = _random.NextFloat(random.Comp.MinRange, random.Comp.MaxRange);
|
||||
}
|
||||
|
||||
private void OnDrawMapInit(Entity<CP14MagicEnergyDrawComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
ent.Comp.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(ent.Comp.Delay);
|
||||
}
|
||||
|
||||
private void UpdateDraw(float frameTime)
|
||||
{
|
||||
UpdateEnergyContainer();
|
||||
UpdateEnergyCrystalSlot();
|
||||
UpdateEnergyRadiusDraw();
|
||||
}
|
||||
|
||||
private void UpdateEnergyContainer()
|
||||
{
|
||||
var query = EntityQueryEnumerator<CP14MagicEnergyDrawComponent, CP14MagicEnergyContainerComponent>();
|
||||
while (query.MoveNext(out var uid, out var draw, out var magicContainer))
|
||||
{
|
||||
if (draw.NextUpdateTime >= _gameTiming.CurTime)
|
||||
continue;
|
||||
|
||||
draw.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(draw.Delay);
|
||||
|
||||
ChangeEnergy(uid, magicContainer, draw.Energy, safe: draw.Safe);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateEnergyCrystalSlot()
|
||||
{
|
||||
var query = EntityQueryEnumerator<CP14MagicEnergyDrawComponent, CP14MagicEnergyCrystalSlotComponent>();
|
||||
while (query.MoveNext(out var uid, out var draw, out var slot))
|
||||
{
|
||||
if (!draw.Enable)
|
||||
continue;
|
||||
|
||||
if (draw.NextUpdateTime >= _gameTiming.CurTime)
|
||||
continue;
|
||||
|
||||
draw.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(draw.Delay);
|
||||
|
||||
if (!_magicSlot.TryGetEnergyCrystalFromSlot(uid, out var energyEnt, out var energyComp))
|
||||
continue;
|
||||
|
||||
ChangeEnergy(energyEnt.Value, energyComp, draw.Energy, draw.Safe);
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateEnergyRadiusDraw()
|
||||
{
|
||||
var query = EntityQueryEnumerator<CP14AuraNodeComponent>();
|
||||
while (query.MoveNext(out var uid, out var draw))
|
||||
{
|
||||
if (!draw.Enable)
|
||||
continue;
|
||||
|
||||
if (draw.NextUpdateTime >= _gameTiming.CurTime)
|
||||
continue;
|
||||
|
||||
draw.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(draw.Delay);
|
||||
|
||||
var containers = _lookup.GetEntitiesInRange<CP14MagicEnergyContainerComponent>(Transform(uid).Coordinates, draw.Range);
|
||||
foreach (var container in containers)
|
||||
{
|
||||
var distance = Vector2.Distance(_transform.GetWorldPosition(uid), _transform.GetWorldPosition(container));
|
||||
var energyDraw = draw.Energy * (1 - distance / draw.Range);
|
||||
|
||||
ChangeEnergy(container, container.Comp, energyDraw, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.Numerics;
|
||||
using Content.Server._CP14.MagicEnergy.Components;
|
||||
using Content.Shared._CP14.MagicEnergy;
|
||||
using Content.Shared._CP14.MagicEnergy.Components;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Content.Shared.Inventory;
|
||||
|
||||
namespace Content.Server._CP14.MagicEnergy;
|
||||
|
||||
public partial class CP14MagicEnergySystem
|
||||
{
|
||||
|
||||
private void InitializeScanner()
|
||||
{
|
||||
SubscribeLocalEvent<CP14MagicEnergyExaminableComponent, ExaminedEvent>(OnExamined);
|
||||
SubscribeLocalEvent<CP14MagicEnergyScannerComponent, CP14MagicEnergyScanEvent>(OnMagicScanAttempt);
|
||||
SubscribeLocalEvent<CP14MagicEnergyScannerComponent, InventoryRelayedEvent<CP14MagicEnergyScanEvent>>((e, c, ev) => OnMagicScanAttempt(e, c, ev.Args));
|
||||
|
||||
SubscribeLocalEvent<CP14AuraScannerComponent, UseInHandEvent>(OnAuraScannerUseInHand);
|
||||
}
|
||||
|
||||
private void OnMagicScanAttempt(EntityUid uid, CP14MagicEnergyScannerComponent component, CP14MagicEnergyScanEvent args)
|
||||
{
|
||||
args.CanScan = true;
|
||||
}
|
||||
|
||||
private void OnExamined(Entity<CP14MagicEnergyExaminableComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
if (!TryComp<CP14MagicEnergyContainerComponent>(ent, out var magicContainer))
|
||||
return;
|
||||
|
||||
var scanEvent = new CP14MagicEnergyScanEvent();
|
||||
RaiseLocalEvent(args.Examiner, scanEvent);
|
||||
|
||||
if (!scanEvent.CanScan)
|
||||
return;
|
||||
|
||||
args.PushMarkup(GetEnergyExaminedText(ent, magicContainer));
|
||||
}
|
||||
|
||||
private void OnAuraScannerUseInHand(Entity<CP14AuraScannerComponent> scanner, ref UseInHandEvent args)
|
||||
{
|
||||
FixedPoint2 sumDraw = 0f;
|
||||
var query = EntityQueryEnumerator<CP14AuraNodeComponent, TransformComponent>();
|
||||
while (query.MoveNext(out var auraUid, out var node, out var xform))
|
||||
{
|
||||
if (xform.MapUid != Transform(scanner).MapUid)
|
||||
continue;
|
||||
|
||||
var distance = Vector2.Distance(_transform.GetWorldPosition(auraUid), _transform.GetWorldPosition(scanner));
|
||||
if (distance > node.Range)
|
||||
continue;
|
||||
|
||||
sumDraw += node.Energy * (1 - distance / node.Range);
|
||||
}
|
||||
_popup.PopupCoordinates(Loc.GetString("cp14-magic-scanner", ("power", sumDraw)), Transform(scanner).Coordinates, args.User);
|
||||
}
|
||||
}
|
||||
@@ -1,152 +1,29 @@
|
||||
using Content.Server._CP14.MagicEnergy.Components;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared._CP14.MagicEnergy;
|
||||
using Content.Shared._CP14.MagicEnergy.Components;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Inventory;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
|
||||
namespace Content.Server._CP14.MagicEnergy;
|
||||
|
||||
public sealed partial class CP14MagicEnergySystem : SharedCP14MagicEnergySystem
|
||||
{
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly IGameTiming _gameTiming = default!;
|
||||
[Dependency] private readonly PointLightSystem _light = default!;
|
||||
[Dependency] private readonly CP14MagicEnergyCrystalSlotSystem _magicSlot = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<CP14MagicEnergyDrawComponent, MapInitEvent>(OnMapInit);
|
||||
SubscribeLocalEvent<CP14MagicEnergyPointLightControllerComponent, CP14MagicEnergyLevelChangeEvent>(OnEnergyChange);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEnergyExaminableComponent, ExaminedEvent>(OnExamined);
|
||||
SubscribeLocalEvent<CP14MagicEnergyScannerComponent, CP14MagicEnergyScanEvent>(OnMagicScanAttempt);
|
||||
SubscribeLocalEvent<CP14MagicEnergyScannerComponent, InventoryRelayedEvent<CP14MagicEnergyScanEvent>>((e, c, ev) => OnMagicScanAttempt(e, c, ev.Args));
|
||||
InitializeDraw();
|
||||
InitializeScanner();
|
||||
}
|
||||
|
||||
private void OnEnergyChange(Entity<CP14MagicEnergyPointLightControllerComponent> ent, ref CP14MagicEnergyLevelChangeEvent args)
|
||||
{
|
||||
if (!TryComp<PointLightComponent>(ent, out var light))
|
||||
return;
|
||||
|
||||
var lightEnergy = MathHelper.Lerp(ent.Comp.MinEnergy, ent.Comp.MaxEnergy, (float)(args.NewValue / args.MaxValue));
|
||||
_light.SetEnergy(ent, lightEnergy, light);
|
||||
}
|
||||
|
||||
private void OnMapInit(Entity<CP14MagicEnergyDrawComponent> ent, ref MapInitEvent args)
|
||||
{
|
||||
ent.Comp.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(ent.Comp.Delay);
|
||||
}
|
||||
|
||||
private void OnMagicScanAttempt(EntityUid uid, CP14MagicEnergyScannerComponent component, CP14MagicEnergyScanEvent args)
|
||||
{
|
||||
args.CanScan = true;
|
||||
}
|
||||
|
||||
private void OnExamined(Entity<CP14MagicEnergyExaminableComponent> ent, ref ExaminedEvent args)
|
||||
{
|
||||
if (!TryComp<CP14MagicEnergyContainerComponent>(ent, out var magicContainer))
|
||||
return;
|
||||
|
||||
var scanEvent = new CP14MagicEnergyScanEvent();
|
||||
RaiseLocalEvent(args.Examiner, scanEvent);
|
||||
|
||||
if (!scanEvent.CanScan)
|
||||
return;
|
||||
|
||||
args.PushMarkup(GetEnergyExaminedText(ent, magicContainer));
|
||||
}
|
||||
|
||||
|
||||
|
||||
public override void Update(float frameTime)
|
||||
{
|
||||
base.Update(frameTime);
|
||||
|
||||
var query = EntityQueryEnumerator<CP14MagicEnergyDrawComponent, CP14MagicEnergyContainerComponent>();
|
||||
while (query.MoveNext(out var uid, out var draw, out var magicContainer))
|
||||
{
|
||||
if (draw.NextUpdateTime >= _gameTiming.CurTime)
|
||||
continue;
|
||||
|
||||
draw.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(draw.Delay);
|
||||
|
||||
ChangeEnergy(uid, magicContainer, draw.Energy, safe: draw.Safe);
|
||||
}
|
||||
|
||||
var query2 = EntityQueryEnumerator<CP14MagicEnergyDrawComponent, CP14MagicEnergyCrystalSlotComponent>();
|
||||
while (query2.MoveNext(out var uid, out var draw, out var slot))
|
||||
{
|
||||
if (!draw.Enable)
|
||||
continue;
|
||||
|
||||
if (draw.NextUpdateTime >= _gameTiming.CurTime)
|
||||
continue;
|
||||
|
||||
draw.NextUpdateTime = _gameTiming.CurTime + TimeSpan.FromSeconds(draw.Delay);
|
||||
|
||||
if (!_magicSlot.TryGetEnergyCrystalFromSlot(uid, out var energyEnt, out var energyComp))
|
||||
continue;
|
||||
|
||||
ChangeEnergy(energyEnt.Value, energyComp, draw.Energy, draw.Safe);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryConsumeEnergy(EntityUid uid, FixedPoint2 energy, CP14MagicEnergyContainerComponent? component = null, bool safe = false)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
|
||||
if (energy <= 0)
|
||||
return true;
|
||||
|
||||
// Attempting to absorb more energy than is contained in the carrier will still waste all the energy
|
||||
if (component.Energy < energy)
|
||||
{
|
||||
ChangeEnergy(uid, component, -component.Energy);
|
||||
return false;
|
||||
}
|
||||
|
||||
ChangeEnergy(uid, component, -energy, safe);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void ChangeEnergy(EntityUid uid, CP14MagicEnergyContainerComponent component, FixedPoint2 energy, bool safe = false)
|
||||
{
|
||||
if (!safe)
|
||||
{
|
||||
//Overload
|
||||
if (component.Energy + energy > component.MaxEnergy)
|
||||
{
|
||||
RaiseLocalEvent(uid, new CP14MagicEnergyOverloadEvent()
|
||||
{
|
||||
OverloadEnergy = (component.Energy + energy) - component.MaxEnergy,
|
||||
});
|
||||
}
|
||||
|
||||
//Burn out
|
||||
if (component.Energy + energy < 0)
|
||||
{
|
||||
RaiseLocalEvent(uid, new CP14MagicEnergyBurnOutEvent()
|
||||
{
|
||||
BurnOutEnergy = -energy - component.Energy
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var oldEnergy = component.Energy;
|
||||
var newEnergy = Math.Clamp((float)component.Energy + (float)energy, 0, (float)component.MaxEnergy);
|
||||
component.Energy = newEnergy;
|
||||
|
||||
if (oldEnergy != newEnergy)
|
||||
{
|
||||
RaiseLocalEvent(uid, new CP14MagicEnergyLevelChangeEvent()
|
||||
{
|
||||
OldValue = component.Energy,
|
||||
NewValue = newEnergy,
|
||||
MaxValue = component.MaxEnergy,
|
||||
});
|
||||
}
|
||||
UpdateDraw(frameTime);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
using Content.Shared.FixedPoint;
|
||||
|
||||
namespace Content.Server._CP14.MagicEnergy.Components;
|
||||
|
||||
[RegisterComponent, Access(typeof(CP14MagicEnergySystem))]
|
||||
public sealed partial class CP14AuraNodeComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public bool Enable = true;
|
||||
|
||||
[DataField]
|
||||
public FixedPoint2 Energy = 1f;
|
||||
|
||||
[DataField]
|
||||
public float Range = 10f;
|
||||
|
||||
/// <summary>
|
||||
/// If not safe, restoring or drawing power across boundaries call dangerous events, that may destroy crystals
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool Safe = true;
|
||||
|
||||
/// <summary>
|
||||
/// how often objects will try to change magic energy. In Seconds
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public float Delay = 5f;
|
||||
|
||||
/// <summary>
|
||||
/// the time of the next magic energy change
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public TimeSpan NextUpdateTime { get; set; } = TimeSpan.Zero;
|
||||
}
|
||||
|
||||
[RegisterComponent, Access(typeof(CP14MagicEnergySystem))]
|
||||
public sealed partial class CP14RandomAuraNodeComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public float MinDraw = -2f;
|
||||
|
||||
[DataField]
|
||||
public float MaxDraw = 2f;
|
||||
|
||||
[DataField]
|
||||
public float MinRange = 5f;
|
||||
|
||||
[DataField]
|
||||
public float MaxRange = 10f;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Content.Server._CP14.MagicEnergy.Components;
|
||||
|
||||
[RegisterComponent, Access(typeof(CP14MagicEnergySystem))]
|
||||
public sealed partial class CP14AuraScannerComponent : Component
|
||||
{
|
||||
}
|
||||
40
Content.Server/_CP14/MagicSpell/CP14MagicSystem.cs
Normal file
40
Content.Server/_CP14/MagicSpell/CP14MagicSystem.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
using Content.Server.Chat.Systems;
|
||||
using Content.Shared._CP14.MagicSpell;
|
||||
using Content.Shared._CP14.MagicSpell.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Events;
|
||||
using Robust.Server.GameObjects;
|
||||
|
||||
namespace Content.Server._CP14.MagicSpell;
|
||||
|
||||
public sealed partial class CP14MagicSystem : CP14SharedMagicSystem
|
||||
{
|
||||
[Dependency] private readonly ChatSystem _chat = default!;
|
||||
[Dependency] private readonly TransformSystem _transform = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14VerbalAspectSpeechEvent>(OnSpellSpoken);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectCastingVisualComponent, CP14StartCastMagicEffectEvent>(OnSpawnMagicVisualEffect);
|
||||
SubscribeLocalEvent<CP14MagicEffectCastingVisualComponent, CP14EndCastMagicEffectEvent>(OnDespawnMagicVisualEffect);
|
||||
}
|
||||
|
||||
private void OnSpellSpoken(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14VerbalAspectSpeechEvent args)
|
||||
{
|
||||
if (args.Performer is not null && args.Speech is not null)
|
||||
_chat.TrySendInGameICMessage(args.Performer.Value, args.Speech, InGameICChatType.Speak, true);
|
||||
}
|
||||
|
||||
private void OnSpawnMagicVisualEffect(Entity<CP14MagicEffectCastingVisualComponent> ent, ref CP14StartCastMagicEffectEvent args)
|
||||
{
|
||||
var vfx = SpawnAttachedTo(ent.Comp.Proto, Transform(args.Performer).Coordinates);
|
||||
_transform.SetParent(vfx, args.Performer);
|
||||
ent.Comp.SpawnedEntity = vfx;
|
||||
}
|
||||
|
||||
private void OnDespawnMagicVisualEffect(Entity<CP14MagicEffectCastingVisualComponent> ent, ref CP14EndCastMagicEffectEvent args)
|
||||
{
|
||||
QueueDel(ent.Comp.SpawnedEntity);
|
||||
ent.Comp.SpawnedEntity = null;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
using Content.Shared.Damage;
|
||||
|
||||
namespace Content.Server._CP14.MeleeWeapon.Components;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14MeleeSelfDamageComponent : Component
|
||||
{
|
||||
[DataField(required: true)]
|
||||
public DamageSpecifier DamageToSelf;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Content.Server._CP14.Objectives.Systems;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server._CP14.Objectives.Components;
|
||||
|
||||
[RegisterComponent, Access(typeof(CP14CurrencyCollectConditionSystem))]
|
||||
public sealed partial class CP14CurrencyCollectConditionComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public int Currency = 1000;
|
||||
|
||||
/// <summary>
|
||||
/// Limits the goal to collecting values from a specific category.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string? Category;
|
||||
|
||||
[DataField(required: true)]
|
||||
public LocId ObjectiveText;
|
||||
|
||||
[DataField(required: true)]
|
||||
public LocId ObjectiveDescription;
|
||||
|
||||
[DataField(required: true)]
|
||||
public SpriteSpecifier ObjectiveSprite;
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
using Content.Server._CP14.Objectives.Components;
|
||||
using Content.Shared._CP14.Currency;
|
||||
using Content.Shared.Mind;
|
||||
using Content.Shared.Mind.Components;
|
||||
using Content.Shared.Movement.Pulling.Components;
|
||||
using Content.Shared.Objectives.Components;
|
||||
using Content.Shared.Objectives.Systems;
|
||||
using Robust.Shared.Containers;
|
||||
|
||||
namespace Content.Server._CP14.Objectives.Systems;
|
||||
|
||||
public sealed class CP14CurrencyCollectConditionSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly MetaDataSystem _metaData = default!;
|
||||
[Dependency] private readonly SharedObjectivesSystem _objectives = default!;
|
||||
[Dependency] private readonly CP14CurrencySystem _currency = default!;
|
||||
|
||||
private EntityQuery<ContainerManagerComponent> _containerQuery;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
_containerQuery = GetEntityQuery<ContainerManagerComponent>();
|
||||
|
||||
SubscribeLocalEvent<CP14CurrencyCollectConditionComponent, ObjectiveAssignedEvent>(OnAssigned);
|
||||
SubscribeLocalEvent<CP14CurrencyCollectConditionComponent, ObjectiveAfterAssignEvent>(OnAfterAssign);
|
||||
SubscribeLocalEvent<CP14CurrencyCollectConditionComponent, ObjectiveGetProgressEvent>(OnGetProgress);
|
||||
}
|
||||
|
||||
private void OnAssigned(Entity<CP14CurrencyCollectConditionComponent> condition, ref ObjectiveAssignedEvent args)
|
||||
{
|
||||
}
|
||||
|
||||
private void OnAfterAssign(Entity<CP14CurrencyCollectConditionComponent> condition, ref ObjectiveAfterAssignEvent args)
|
||||
{
|
||||
_metaData.SetEntityName(condition.Owner, Loc.GetString(condition.Comp.ObjectiveText), args.Meta);
|
||||
_metaData.SetEntityDescription(condition.Owner, Loc.GetString(condition.Comp.ObjectiveDescription, ("coins", _currency.GetPrettyCurrency(condition.Comp.Currency))), args.Meta);
|
||||
_objectives.SetIcon(condition.Owner, condition.Comp.ObjectiveSprite);
|
||||
}
|
||||
|
||||
private void OnGetProgress(Entity<CP14CurrencyCollectConditionComponent> condition, ref ObjectiveGetProgressEvent args)
|
||||
{
|
||||
args.Progress = GetProgress(args.Mind, condition);
|
||||
}
|
||||
|
||||
private float GetProgress(MindComponent mind, CP14CurrencyCollectConditionComponent condition)
|
||||
{
|
||||
if (!_containerQuery.TryGetComponent(mind.OwnedEntity, out var currentManager))
|
||||
return 0;
|
||||
|
||||
var containerStack = new Stack<ContainerManagerComponent>();
|
||||
var count = 0;
|
||||
|
||||
//check pulling object
|
||||
if (TryComp<PullerComponent>(mind.OwnedEntity, out var pull)) //TO DO: to make the code prettier? don't like the repetition
|
||||
{
|
||||
var pulledEntity = pull.Pulling;
|
||||
if (pulledEntity != null)
|
||||
{
|
||||
CheckEntity(pulledEntity.Value, condition, ref containerStack, ref count);
|
||||
}
|
||||
}
|
||||
|
||||
// recursively check each container for the item
|
||||
// checks inventory, bag, implants, etc.
|
||||
do
|
||||
{
|
||||
foreach (var container in currentManager.Containers.Values)
|
||||
{
|
||||
foreach (var entity in container.ContainedEntities)
|
||||
{
|
||||
// check if this is the item
|
||||
count += CheckCurrency(entity, condition);
|
||||
|
||||
// if it is a container check its contents
|
||||
if (_containerQuery.TryGetComponent(entity, out var containerManager))
|
||||
containerStack.Push(containerManager);
|
||||
}
|
||||
}
|
||||
} while (containerStack.TryPop(out currentManager));
|
||||
|
||||
var result = count / (float) condition.Currency;
|
||||
result = Math.Clamp(result, 0, 1);
|
||||
return result;
|
||||
}
|
||||
|
||||
private void CheckEntity(EntityUid entity, CP14CurrencyCollectConditionComponent condition, ref Stack<ContainerManagerComponent> containerStack, ref int counter)
|
||||
{
|
||||
// check if this is the item
|
||||
counter += CheckCurrency(entity, condition);
|
||||
|
||||
//we don't check the inventories of sentient entity
|
||||
if (!TryComp<MindContainerComponent>(entity, out _))
|
||||
{
|
||||
// if it is a container check its contents
|
||||
if (_containerQuery.TryGetComponent(entity, out var containerManager))
|
||||
containerStack.Push(containerManager);
|
||||
}
|
||||
}
|
||||
|
||||
private int CheckCurrency(EntityUid entity, CP14CurrencyCollectConditionComponent condition)
|
||||
{
|
||||
// check if this is the target
|
||||
if (!TryComp<CP14CurrencyComponent>(entity, out var target))
|
||||
return 0;
|
||||
|
||||
if (target.Category != condition.Category)
|
||||
return 0;
|
||||
|
||||
return _currency.GetTotalCurrency(entity);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using Robust.Shared.Audio;
|
||||
|
||||
namespace Content.Server._CP14.PersonalSignature;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed partial class CP14PersonalSignatureComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public SoundSpecifier? SignSound;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Server.Mind;
|
||||
using Content.Server.Paper;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Paper;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Player;
|
||||
|
||||
namespace Content.Server._CP14.PersonalSignature;
|
||||
|
||||
public sealed class CP14PersonalSignatureSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AudioSystem _audio = default!;
|
||||
[Dependency] private readonly MindSystem _mind = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<PaperComponent, GetVerbsEvent<AlternativeVerb>>(OnGetVerb);
|
||||
}
|
||||
|
||||
private void OnGetVerb(Entity<PaperComponent> entity, ref GetVerbsEvent<AlternativeVerb> args)
|
||||
{
|
||||
if (!_mind.TryGetMind(args.User, out _, out var mind))
|
||||
return;
|
||||
|
||||
if (mind.CharacterName is null)
|
||||
return;
|
||||
|
||||
if (!CanSign(args.Using, out var signature))
|
||||
return;
|
||||
|
||||
if (HasSign(entity, mind.CharacterName))
|
||||
return;
|
||||
|
||||
args.Verbs.Add(new AlternativeVerb
|
||||
{
|
||||
Text = Loc.GetString("cp-sign-verb"),
|
||||
Act = () =>
|
||||
{
|
||||
Sign(entity, mind.CharacterName, signature.SignSound);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
private bool CanSign(EntityUid? item, [NotNullWhen(true)] out CP14PersonalSignatureComponent? personalSignature)
|
||||
{
|
||||
personalSignature = null;
|
||||
return item is not null && TryComp(item, out personalSignature);
|
||||
}
|
||||
|
||||
private bool HasSign(Entity<PaperComponent> entity, string sign)
|
||||
{
|
||||
foreach (var info in entity.Comp.StampedBy)
|
||||
{
|
||||
if (info.StampedName == sign)
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void Sign(Entity<PaperComponent> target, string name, SoundSpecifier? sound)
|
||||
{
|
||||
var info = new StampDisplayInfo
|
||||
{
|
||||
StampedName = name,
|
||||
StampedColor = Color.Gray,
|
||||
};
|
||||
|
||||
if (sound is not null)
|
||||
_audio.PlayEntity(sound, Filter.Pvs(target), target, true);
|
||||
|
||||
target.Comp.StampedBy.Add(info);
|
||||
}
|
||||
}
|
||||
21
Content.Server/_CP14/RoundSeed/CP14RoundSeedComponent.cs
Normal file
21
Content.Server/_CP14/RoundSeed/CP14RoundSeedComponent.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* All right reserved to CrystallPunk.
|
||||
*
|
||||
* BUT this file is sublicensed under MIT License
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Content.Server._CP14.RoundSeed;
|
||||
|
||||
/// <summary>
|
||||
/// This is used for round seed
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14RoundSeedSystem))]
|
||||
public sealed partial class CP14RoundSeedComponent : Component
|
||||
{
|
||||
[ViewVariables]
|
||||
public static int MaxValue = 10000;
|
||||
|
||||
[ViewVariables]
|
||||
public int Seed;
|
||||
}
|
||||
53
Content.Server/_CP14/RoundSeed/CP14RoundSeedSystem.cs
Normal file
53
Content.Server/_CP14/RoundSeed/CP14RoundSeedSystem.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* All right reserved to CrystallPunk.
|
||||
*
|
||||
* BUT this file is sublicensed under MIT License
|
||||
*
|
||||
*/
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Server._CP14.RoundSeed;
|
||||
|
||||
/// <summary>
|
||||
/// Provides a round seed for another systems
|
||||
/// </summary>
|
||||
public sealed class CP14RoundSeedSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<CP14RoundSeedComponent, ComponentStartup>(OnComponentStartup);
|
||||
}
|
||||
|
||||
private void OnComponentStartup(Entity<CP14RoundSeedComponent> ent, ref ComponentStartup args)
|
||||
{
|
||||
ent.Comp.Seed = _random.Next(CP14RoundSeedComponent.MaxValue);
|
||||
}
|
||||
|
||||
private int SetupSeed()
|
||||
{
|
||||
return AddComp<CP14RoundSeedComponent>(Spawn(null, MapCoordinates.Nullspace)).Seed;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the round seed if assigned, otherwise assigns the round seed itself.
|
||||
/// </summary>
|
||||
/// <returns>seed of the round</returns>
|
||||
public int GetSeed()
|
||||
{
|
||||
var query = EntityQuery<CP14RoundSeedComponent>();
|
||||
foreach (var comp in query)
|
||||
{
|
||||
return comp.Seed;
|
||||
}
|
||||
|
||||
var seed = SetupSeed();
|
||||
Log.Warning($"Missing RoundSeed. Seed set to {seed}");
|
||||
return seed;
|
||||
}
|
||||
}
|
||||
@@ -29,21 +29,31 @@ public sealed class CP14ExpeditionSystem : EntitySystem
|
||||
/// </summary>
|
||||
public float ArrivalTime { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// If enabled then spawns players on an expedition ship.
|
||||
/// </summary>
|
||||
public bool Enabled { get; private set; }
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14StationExpeditionTargetComponent, StationPostInitEvent>(OnPostInitSetupExpeditionShip);
|
||||
|
||||
SubscribeLocalEvent<CP14StationExpeditionTargetComponent, FTLCompletedEvent>(OnArrivalsDocked);
|
||||
SubscribeLocalEvent<CP14StationExpeditionTargetComponent, FTLCompletedEvent>(OnExpeditionShipLanded);
|
||||
|
||||
ArrivalTime = _cfgManager.GetCVar(CCVars.CP14ExpeditionArrivalTime);
|
||||
_cfgManager.OnValueChanged(CCVars.CP14ExpeditionArrivalTime, time => ArrivalTime = time, true);
|
||||
}
|
||||
Enabled = _cfgManager.GetCVar(CCVars.CP14ExpeditionShip);
|
||||
|
||||
_cfgManager.OnValueChanged(CCVars.CP14ExpeditionArrivalTime, time => ArrivalTime = time, true);
|
||||
_cfgManager.OnValueChanged(CCVars.CP14ExpeditionShip, value => Enabled = value, true);
|
||||
}
|
||||
|
||||
private void OnPostInitSetupExpeditionShip(Entity<CP14StationExpeditionTargetComponent> station, ref StationPostInitEvent args)
|
||||
{
|
||||
if (!Enabled)
|
||||
return;
|
||||
|
||||
if (!Deleted(station.Comp.Shuttle))
|
||||
return;
|
||||
|
||||
@@ -76,7 +86,7 @@ public sealed class CP14ExpeditionSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
private void OnArrivalsDocked(Entity<CP14StationExpeditionTargetComponent> ent, ref FTLCompletedEvent args)
|
||||
private void OnExpeditionShipLanded(Entity<CP14StationExpeditionTargetComponent> ent, ref FTLCompletedEvent args)
|
||||
{
|
||||
//Some announsement logic?
|
||||
}
|
||||
@@ -97,6 +107,9 @@ public sealed class CP14ExpeditionSystem : EntitySystem
|
||||
|
||||
public void HandlePlayerSpawning(PlayerSpawningEvent ev)
|
||||
{
|
||||
if (!Enabled)
|
||||
return;
|
||||
|
||||
if (ev.SpawnResult != null)
|
||||
return;
|
||||
|
||||
@@ -114,8 +127,10 @@ public sealed class CP14ExpeditionSystem : EntitySystem
|
||||
var possiblePositions = new List<EntityCoordinates>();
|
||||
while (points.MoveNext(out var uid, out var spawnPoint, out var xform))
|
||||
{
|
||||
if (ev.Job != null && spawnPoint.Job != ev.Job.Prototype)
|
||||
continue;
|
||||
|
||||
if (spawnPoint.SpawnType != SpawnPointType.LateJoin || xform.GridUid != gridUid)
|
||||
if (xform.GridUid != gridUid)
|
||||
continue;
|
||||
|
||||
possiblePositions.Add(xform.Coordinates);
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
using System.Numerics;
|
||||
using Content.Server._CP14.Alchemy;
|
||||
using Content.Server._CP14.MeleeWeapon;
|
||||
using Content.Server._CP14.MeleeWeapon.EntitySystems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared._CP14.MeleeWeapon.EntitySystems;
|
||||
using Content.Shared._CP14.Skills;
|
||||
using Content.Shared._CP14.Skills.Components;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Stunnable;
|
||||
using Content.Shared.Throwing;
|
||||
using Content.Shared.Weapons.Melee;
|
||||
using Content.Shared.Weapons.Melee.Events;
|
||||
|
||||
@@ -3,7 +3,7 @@ using Robust.Shared.Utility;
|
||||
namespace Content.Server._CP14.StationDungeonMap;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a procedurally generated world with points of interest
|
||||
/// Loads additional maps from the list at the start of the round.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14StationAdditionalMapSystem))]
|
||||
public sealed partial class CP14StationAdditionalMapComponent : Component
|
||||
|
||||
33
Content.Server/_CP14/Workbench/CP14WorkbenchSystem.UI.cs
Normal file
33
Content.Server/_CP14/Workbench/CP14WorkbenchSystem.UI.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using Content.Shared._CP14.Workbench;
|
||||
|
||||
namespace Content.Server._CP14.Workbench;
|
||||
|
||||
public sealed partial class CP14WorkbenchSystem
|
||||
{
|
||||
private void OnCraft(Entity<CP14WorkbenchComponent> entity, ref CP14WorkbenchUiCraftMessage args)
|
||||
{
|
||||
if (!entity.Comp.Recipes.Contains(args.Recipe))
|
||||
return;
|
||||
|
||||
if (!_proto.TryIndex(args.Recipe, out var prototype))
|
||||
return;
|
||||
|
||||
StartCraft(entity, args.Actor, prototype);
|
||||
}
|
||||
|
||||
private void UpdateUIRecipes(Entity<CP14WorkbenchComponent> entity)
|
||||
{
|
||||
var placedEntities = _lookup.GetEntitiesInRange(Transform(entity).Coordinates, WorkbenchRadius);
|
||||
|
||||
var recipes = new List<CP14WorkbenchUiRecipesEntry>();
|
||||
foreach (var recipeId in entity.Comp.Recipes)
|
||||
{
|
||||
var recipe = _proto.Index(recipeId);
|
||||
var entry = new CP14WorkbenchUiRecipesEntry(recipeId, CanCraftRecipe(recipe, placedEntities));
|
||||
|
||||
recipes.Add(entry);
|
||||
}
|
||||
|
||||
_userInterface.SetUiState(entity.Owner, CP14WorkbenchUiKey.Key, new CP14WorkbenchUiRecipesState(recipes));
|
||||
}
|
||||
}
|
||||
@@ -1,26 +1,32 @@
|
||||
using Content.Server.DoAfter;
|
||||
using Content.Server.Popups;
|
||||
using Content.Server.Stack;
|
||||
using Content.Shared._CP14.Workbench;
|
||||
using Content.Shared._CP14.Workbench.Prototypes;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Stacks;
|
||||
using Content.Shared.UserInterface;
|
||||
using Content.Shared.Verbs;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server._CP14.Workbench;
|
||||
|
||||
public sealed class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
|
||||
public sealed partial class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
|
||||
{
|
||||
[Dependency] private readonly SharedAudioSystem _audio = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||
[Dependency] private readonly SharedStackSystem _stack = default!;
|
||||
[Dependency] private readonly AudioSystem _audio = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly DoAfterSystem _doAfter = default!;
|
||||
[Dependency] private readonly StackSystem _stack = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly PopupSystem _popup = default!;
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly UserInterfaceSystem _userInterface = default!;
|
||||
|
||||
private EntityQuery<MetaDataComponent> _metaQuery;
|
||||
private EntityQuery<StackComponent> _stackQuery;
|
||||
|
||||
// Why not in component? Why?
|
||||
private const float WorkbenchRadius = 0.5f;
|
||||
|
||||
public override void Initialize()
|
||||
@@ -30,10 +36,18 @@ public sealed class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
|
||||
_metaQuery = GetEntityQuery<MetaDataComponent>();
|
||||
_stackQuery = GetEntityQuery<StackComponent>();
|
||||
|
||||
SubscribeLocalEvent<CP14WorkbenchComponent, BeforeActivatableUIOpenEvent>(OnBeforeUIOpen);
|
||||
SubscribeLocalEvent<CP14WorkbenchComponent, CP14WorkbenchUiCraftMessage>(OnCraft);
|
||||
|
||||
SubscribeLocalEvent<CP14WorkbenchComponent, GetVerbsEvent<InteractionVerb>>(OnInteractionVerb);
|
||||
SubscribeLocalEvent<CP14WorkbenchComponent, CP14CraftDoAfterEvent>(OnCraftFinished);
|
||||
}
|
||||
|
||||
private void OnBeforeUIOpen(Entity<CP14WorkbenchComponent> ent, ref BeforeActivatableUIOpenEvent args)
|
||||
{
|
||||
UpdateUIRecipes(ent);
|
||||
}
|
||||
|
||||
private void OnInteractionVerb(Entity<CP14WorkbenchComponent> ent, ref GetVerbsEvent<InteractionVerb> args)
|
||||
{
|
||||
if (!args.CanAccess || !args.CanInteract || args.Hands is null)
|
||||
@@ -64,6 +78,7 @@ public sealed class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Replace Del to QueueDel when it's will be works with events
|
||||
private void OnCraftFinished(Entity<CP14WorkbenchComponent> ent, ref CP14CraftDoAfterEvent args)
|
||||
{
|
||||
if (args.Cancelled || args.Handled)
|
||||
@@ -89,7 +104,7 @@ public sealed class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
|
||||
if (placedProto != null && placedProto == requiredIngredient.Key && requiredCount > 0)
|
||||
{
|
||||
requiredCount--;
|
||||
QueueDel(placedEntity);
|
||||
Del(placedEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -106,14 +121,18 @@ public sealed class CP14WorkbenchSystem : SharedCP14WorkbenchSystem
|
||||
continue;
|
||||
|
||||
var count = (int)MathF.Min(requiredCount, stack.Count);
|
||||
_stack.SetCount(placedEntity, stack.Count - count, stack);
|
||||
|
||||
if (stack.Count - count <= 0)
|
||||
Del(placedEntity);
|
||||
else
|
||||
_stack.SetCount(placedEntity, stack.Count - count, stack);
|
||||
|
||||
requiredCount -= count;
|
||||
}
|
||||
}
|
||||
|
||||
Spawn(_proto.Index(args.Recipe).Result, Transform(ent).Coordinates);
|
||||
|
||||
UpdateUIRecipes(ent);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -183,6 +183,30 @@ public partial class SharedBodySystem
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of Entity<<see cref="T"/>, <see cref="OrganComponent"/>>
|
||||
/// for each organ of the body
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The component that we want to return</typeparam>
|
||||
/// <param name="entity">The body to check the organs of</param>
|
||||
public List<Entity<T, OrganComponent>> GetBodyOrganEntityComps<T>(
|
||||
Entity<BodyComponent?> entity)
|
||||
where T : IComponent
|
||||
{
|
||||
if (!Resolve(entity, ref entity.Comp))
|
||||
return new List<Entity<T, OrganComponent>>();
|
||||
|
||||
var query = GetEntityQuery<T>();
|
||||
var list = new List<Entity<T, OrganComponent>>(3);
|
||||
foreach (var organ in GetBodyOrgans(entity.Owner, entity.Comp))
|
||||
{
|
||||
if (query.TryGetComponent(organ.Id, out var comp))
|
||||
list.Add((organ.Id, comp, organ.Component));
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get a list of ValueTuples of <see cref="T"/> and OrganComponent on each organs
|
||||
/// in the given body.
|
||||
|
||||
@@ -11,11 +11,17 @@ namespace Content.Shared.CCVar
|
||||
public sealed class CCVars : CVars
|
||||
{
|
||||
#region CP14
|
||||
|
||||
/// <summary>
|
||||
/// how long does it take to fly an expedition ship to an expedition point?
|
||||
/// </summary>
|
||||
public static readonly CVarDef<float> CP14ExpeditionArrivalTime =
|
||||
CVarDef.Create("cp14.arrival_time", 60f, CVar.SERVERONLY);
|
||||
|
||||
CVarDef.Create("cp14.arrival_time", 180f, CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// is the expedition ship's system enabled?
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> CP14ExpeditionShip =
|
||||
CVarDef.Create("cp14.arrivals_ship", true, CVar.SERVERONLY);
|
||||
#endregion
|
||||
/*
|
||||
* Server
|
||||
@@ -511,7 +517,7 @@ namespace Content.Shared.CCVar
|
||||
/// The dataset prototype to use when selecting a random tip.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<string> TipsDataset =
|
||||
CVarDef.Create("tips.dataset", "Tips");
|
||||
CVarDef.Create("tips.dataset", "CP14Tips");
|
||||
|
||||
/// <summary>
|
||||
/// The number of seconds between each tip being displayed when the round is not actively going
|
||||
@@ -1473,7 +1479,7 @@ namespace Content.Shared.CCVar
|
||||
/// Whether the arrivals shuttle is enabled.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> ArrivalsShuttles =
|
||||
CVarDef.Create("shuttle.arrivals", true, CVar.SERVERONLY);
|
||||
CVarDef.Create("shuttle.arrivals", false, CVar.SERVERONLY); //CP14 arrivals disabled
|
||||
|
||||
/// <summary>
|
||||
/// The map to use for the arrivals station.
|
||||
@@ -1505,6 +1511,13 @@ namespace Content.Shared.CCVar
|
||||
public static readonly CVarDef<bool> GodmodeArrivals =
|
||||
CVarDef.Create("shuttle.godmode_arrivals", false, CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// If a grid is split then hide any smaller ones under this mass (kg) from the map.
|
||||
/// This is useful to avoid split grids spamming out labels.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<int> HideSplitGridsUnder =
|
||||
CVarDef.Create("shuttle.hide_split_grids_under", 30, CVar.SERVERONLY);
|
||||
|
||||
/// <summary>
|
||||
/// Whether to automatically spawn escape shuttles.
|
||||
/// </summary>
|
||||
@@ -1593,7 +1606,7 @@ namespace Content.Shared.CCVar
|
||||
/// Whether the emergency shuttle is enabled or should the round just end.
|
||||
/// </summary>
|
||||
public static readonly CVarDef<bool> EmergencyShuttleEnabled =
|
||||
CVarDef.Create("shuttle.emergency", true, CVar.SERVERONLY);
|
||||
CVarDef.Create("shuttle.emergency", false, CVar.SERVERONLY); //CP14 Emergency disabled
|
||||
|
||||
/// <summary>
|
||||
/// The percentage of time passed from the initial call to when the shuttle can no longer be recalled.
|
||||
|
||||
@@ -87,6 +87,22 @@ public sealed partial class InjectorComponent : Component
|
||||
[AutoNetworkedField]
|
||||
[DataField]
|
||||
public InjectorToggleMode ToggleState = InjectorToggleMode.Draw;
|
||||
|
||||
#region Arguments for injection doafter
|
||||
|
||||
/// <inheritdoc cref=DoAfterArgs.NeedHand>
|
||||
[DataField]
|
||||
public bool NeedHand = true;
|
||||
|
||||
/// <inheritdoc cref=DoAfterArgs.BreakOnHandChange>
|
||||
[DataField]
|
||||
public bool BreakOnHandChange = true;
|
||||
|
||||
/// <inheritdoc cref=DoAfterArgs.MovementThreshold>
|
||||
[DataField]
|
||||
public float MovementThreshold = 0.1f;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -58,7 +58,7 @@ namespace Content.Shared.Cuffs
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<HandCountChangedEvent>(OnHandCountChanged);
|
||||
SubscribeLocalEvent<CuffableComponent, HandCountChangedEvent>(OnHandCountChanged);
|
||||
SubscribeLocalEvent<UncuffAttemptEvent>(OnUncuffAttempt);
|
||||
|
||||
SubscribeLocalEvent<CuffableComponent, EntRemovedFromContainerMessage>(OnCuffsRemovedFromContainer);
|
||||
@@ -380,33 +380,24 @@ namespace Content.Shared.Cuffs
|
||||
/// <summary>
|
||||
/// Check the current amount of hands the owner has, and if there's less hands than active cuffs we remove some cuffs.
|
||||
/// </summary>
|
||||
private void OnHandCountChanged(HandCountChangedEvent message)
|
||||
private void OnHandCountChanged(Entity<CuffableComponent> ent, ref HandCountChangedEvent message)
|
||||
{
|
||||
var owner = message.Sender;
|
||||
|
||||
if (!TryComp(owner, out CuffableComponent? cuffable) ||
|
||||
!cuffable.Initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var dirty = false;
|
||||
var handCount = CompOrNull<HandsComponent>(owner)?.Count ?? 0;
|
||||
var handCount = CompOrNull<HandsComponent>(ent.Owner)?.Count ?? 0;
|
||||
|
||||
while (cuffable.CuffedHandCount > handCount && cuffable.CuffedHandCount > 0)
|
||||
while (ent.Comp.CuffedHandCount > handCount && ent.Comp.CuffedHandCount > 0)
|
||||
{
|
||||
dirty = true;
|
||||
|
||||
var container = cuffable.Container;
|
||||
var entity = container.ContainedEntities[^1];
|
||||
var handcuffContainer = ent.Comp.Container;
|
||||
var handcuffEntity = handcuffContainer.ContainedEntities[^1];
|
||||
|
||||
_container.Remove(entity, container);
|
||||
_transform.SetWorldPosition(entity, _transform.GetWorldPosition(owner));
|
||||
_transform.PlaceNextTo(handcuffEntity, ent.Owner);
|
||||
}
|
||||
|
||||
if (dirty)
|
||||
{
|
||||
UpdateCuffState(owner, cuffable);
|
||||
UpdateCuffState(ent.Owner, ent.Comp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Map.Components;
|
||||
|
||||
namespace Content.Shared.Doors.Systems;
|
||||
|
||||
@@ -40,6 +41,8 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
||||
[Dependency] private readonly AccessReaderSystem _accessReaderSystem = default!;
|
||||
[Dependency] private readonly PryingSystem _pryingSystem = default!;
|
||||
[Dependency] protected readonly SharedPopupSystem Popup = default!;
|
||||
[Dependency] private readonly SharedMapSystem _mapSystem = default!;
|
||||
|
||||
|
||||
[ValidatePrototypeId<TagPrototype>]
|
||||
public const string DoorBumpTag = "DoorBumpOpener";
|
||||
@@ -546,29 +549,37 @@ public abstract partial class SharedDoorSystem : EntitySystem
|
||||
if (!Resolve(uid, ref physics))
|
||||
yield break;
|
||||
|
||||
var xform = Transform(uid);
|
||||
// Getting the world bounds from the gridUid allows us to use the version of
|
||||
// GetCollidingEntities that returns Entity<PhysicsComponent>
|
||||
if (!TryComp<MapGridComponent>(xform.GridUid, out var mapGridComp))
|
||||
yield break;
|
||||
var tileRef = _mapSystem.GetTileRef(xform.GridUid.Value, mapGridComp, xform.Coordinates);
|
||||
var doorWorldBounds = _entityLookup.GetWorldBounds(tileRef);
|
||||
|
||||
// TODO SLOTH fix electro's code.
|
||||
// ReSharper disable once InconsistentNaming
|
||||
var doorAABB = _entityLookup.GetWorldAABB(uid);
|
||||
|
||||
foreach (var otherPhysics in PhysicsSystem.GetCollidingEntities(Transform(uid).MapID, doorAABB))
|
||||
foreach (var otherPhysics in PhysicsSystem.GetCollidingEntities(Transform(uid).MapID, doorWorldBounds))
|
||||
{
|
||||
if (otherPhysics == physics)
|
||||
if (otherPhysics.Comp == physics)
|
||||
continue;
|
||||
|
||||
//TODO: Make only shutters ignore these objects upon colliding instead of all airlocks
|
||||
// Excludes Glasslayer for windows, GlassAirlockLayer for windoors, TableLayer for tables
|
||||
if (!otherPhysics.CanCollide || otherPhysics.CollisionLayer == (int)CollisionGroup.GlassLayer || otherPhysics.CollisionLayer == (int)CollisionGroup.GlassAirlockLayer || otherPhysics.CollisionLayer == (int)CollisionGroup.TableLayer)
|
||||
if (!otherPhysics.Comp.CanCollide || otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.GlassLayer || otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.GlassAirlockLayer || otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.TableLayer)
|
||||
continue;
|
||||
|
||||
//If the colliding entity is a slippable item ignore it by the airlock
|
||||
if (otherPhysics.CollisionLayer == (int)CollisionGroup.SlipLayer && otherPhysics.CollisionMask == (int)CollisionGroup.ItemMask)
|
||||
if (otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.SlipLayer && otherPhysics.Comp.CollisionMask == (int) CollisionGroup.ItemMask)
|
||||
continue;
|
||||
|
||||
//For when doors need to close over conveyor belts
|
||||
if (otherPhysics.CollisionLayer == (int) CollisionGroup.ConveyorMask)
|
||||
if (otherPhysics.Comp.CollisionLayer == (int) CollisionGroup.ConveyorMask)
|
||||
continue;
|
||||
|
||||
if ((physics.CollisionMask & otherPhysics.CollisionLayer) == 0 && (otherPhysics.CollisionMask & physics.CollisionLayer) == 0)
|
||||
if ((physics.CollisionMask & otherPhysics.Comp.CollisionLayer) == 0 && (otherPhysics.Comp.CollisionMask & physics.CollisionLayer) == 0)
|
||||
continue;
|
||||
|
||||
if (_entityLookup.GetWorldAABB(otherPhysics.Owner).IntersectPercentage(doorAABB) < IntersectPercentage)
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Content.Shared.Examine
|
||||
{
|
||||
public abstract partial class ExamineSystemShared : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly OccluderSystem _occluder = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
|
||||
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
|
||||
@@ -182,12 +183,9 @@ namespace Content.Shared.Examine
|
||||
length = MaxRaycastRange;
|
||||
}
|
||||
|
||||
var occluderSystem = Get<OccluderSystem>();
|
||||
IoCManager.Resolve(ref entMan);
|
||||
|
||||
var ray = new Ray(origin.Position, dir.Normalized());
|
||||
var rayResults = occluderSystem
|
||||
.IntersectRayWithPredicate(origin.MapId, ray, length, state, predicate, false).ToList();
|
||||
var rayResults = _occluder
|
||||
.IntersectRayWithPredicate(origin.MapId, ray, length, state, predicate, false);
|
||||
|
||||
if (rayResults.Count == 0) return true;
|
||||
|
||||
@@ -195,13 +193,13 @@ namespace Content.Shared.Examine
|
||||
|
||||
foreach (var result in rayResults)
|
||||
{
|
||||
if (!entMan.TryGetComponent(result.HitEntity, out OccluderComponent? o))
|
||||
if (!TryComp(result.HitEntity, out OccluderComponent? o))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var bBox = o.BoundingBox;
|
||||
bBox = bBox.Translated(entMan.GetComponent<TransformComponent>(result.HitEntity).WorldPosition);
|
||||
bBox = bBox.Translated(_transform.GetWorldPosition(result.HitEntity));
|
||||
|
||||
if (bBox.Contains(origin.Position) || bBox.Contains(other.Position))
|
||||
{
|
||||
@@ -216,7 +214,6 @@ namespace Content.Shared.Examine
|
||||
|
||||
public bool InRangeUnOccluded(EntityUid origin, EntityUid other, float range = ExamineRange, Ignored? predicate = null, bool ignoreInsideBlocker = true)
|
||||
{
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
var originPos = _transform.GetMapCoordinates(origin);
|
||||
var otherPos = _transform.GetMapCoordinates(other);
|
||||
|
||||
@@ -225,16 +222,14 @@ namespace Content.Shared.Examine
|
||||
|
||||
public bool InRangeUnOccluded(EntityUid origin, EntityCoordinates other, float range = ExamineRange, Ignored? predicate = null, bool ignoreInsideBlocker = true)
|
||||
{
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
var originPos = _transform.GetMapCoordinates(origin);
|
||||
var otherPos = other.ToMap(entMan, _transform);
|
||||
var otherPos = _transform.ToMapCoordinates(other);
|
||||
|
||||
return InRangeUnOccluded(originPos, otherPos, range, predicate, ignoreInsideBlocker);
|
||||
}
|
||||
|
||||
public bool InRangeUnOccluded(EntityUid origin, MapCoordinates other, float range = ExamineRange, Ignored? predicate = null, bool ignoreInsideBlocker = true)
|
||||
{
|
||||
var entMan = IoCManager.Resolve<IEntityManager>();
|
||||
var originPos = _transform.GetMapCoordinates(origin);
|
||||
|
||||
return InRangeUnOccluded(originPos, other, range, predicate, ignoreInsideBlocker);
|
||||
@@ -250,11 +245,12 @@ namespace Content.Shared.Examine
|
||||
}
|
||||
|
||||
var hasDescription = false;
|
||||
var metadata = MetaData(entity);
|
||||
|
||||
//Add an entity description if one is declared
|
||||
if (!string.IsNullOrEmpty(EntityManager.GetComponent<MetaDataComponent>(entity).EntityDescription))
|
||||
if (!string.IsNullOrEmpty(metadata.EntityDescription))
|
||||
{
|
||||
message.AddText(EntityManager.GetComponent<MetaDataComponent>(entity).EntityDescription);
|
||||
message.AddText(metadata.EntityDescription);
|
||||
hasDescription = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,12 +7,13 @@ namespace Content.Shared.Humanoid
|
||||
{
|
||||
public static bool HasSexMorph(HumanoidVisualLayers layer)
|
||||
{
|
||||
return layer switch
|
||||
{
|
||||
HumanoidVisualLayers.Chest => true,
|
||||
HumanoidVisualLayers.Head => true,
|
||||
_ => false
|
||||
};
|
||||
return true; //Support female body
|
||||
//return layer switch
|
||||
//{
|
||||
// HumanoidVisualLayers.Chest => true,
|
||||
// HumanoidVisualLayers.Head => true,
|
||||
// _ => false
|
||||
//};
|
||||
}
|
||||
|
||||
public static string GetSexMorph(HumanoidVisualLayers layer, Sex sex, string id)
|
||||
|
||||
@@ -26,9 +26,8 @@ namespace Content.Shared.Localizations
|
||||
public void Initialize()
|
||||
{
|
||||
var culture = new CultureInfo(Culture);
|
||||
// Uncomment for Ru localization
|
||||
_loc.LoadCulture(culture);
|
||||
|
||||
// Uncomment for Ru localization
|
||||
var fallbackCulture = new CultureInfo("en-US");
|
||||
_loc.LoadCulture(fallbackCulture);
|
||||
_loc.SetFallbackCluture(fallbackCulture);
|
||||
|
||||
@@ -92,6 +92,13 @@ public sealed partial class LockComponent : Component
|
||||
[ByRefEvent]
|
||||
public record struct LockToggleAttemptEvent(EntityUid User, bool Silent = false, bool Cancelled = false);
|
||||
|
||||
/// <summary>
|
||||
/// Event raised on the user when a toggle is attempted.
|
||||
/// Can be cancelled to prevent it.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public record struct UserLockToggleAttemptEvent(EntityUid Target, bool Silent = false, bool Cancelled = false);
|
||||
|
||||
/// <summary>
|
||||
/// Event raised on a lock after it has been toggled.
|
||||
/// </summary>
|
||||
|
||||
@@ -109,17 +109,14 @@ public sealed class LockSystem : EntitySystem
|
||||
//CrystallPunk Lock System Adapt Start
|
||||
if (lockComp.LockSlotId != null && _lockCp14.TryGetLockFromSlot(uid, out var lockEnt))
|
||||
{
|
||||
args.PushText(Loc.GetString("cp-lock-examine-lock-slot", ("lock", MetaData(lockEnt.Value).EntityName)));
|
||||
args.PushText(Loc.GetString("cp14-lock-examine-lock-slot", ("lock", MetaData(lockEnt.Value).EntityName)));
|
||||
|
||||
args.PushMarkup(Loc.GetString(lockComp.Locked
|
||||
? "lock-comp-on-examined-is-locked"
|
||||
: "lock-comp-on-examined-is-unlocked",
|
||||
("entityName", Identity.Name(uid, EntityManager))));
|
||||
if (lockEnt.Value.Comp.LockpickeddFailMarkup)
|
||||
args.PushMarkup(Loc.GetString("cp-lock-examine-lock-lockpicked", ("lock", MetaData(lockEnt.Value).EntityName)));
|
||||
} else
|
||||
{
|
||||
args.PushText(Loc.GetString("cp-lock-examine-lock-null"));
|
||||
args.PushMarkup(Loc.GetString("cp14-lock-examine-lock-lockpicked", ("lock", MetaData(lockEnt.Value).EntityName)));
|
||||
}
|
||||
//CrystallPunk Lock System Adapt End
|
||||
}
|
||||
@@ -158,7 +155,7 @@ public sealed class LockSystem : EntitySystem
|
||||
|
||||
_sharedPopupSystem.PopupClient(Loc.GetString("lock-comp-do-lock-success",
|
||||
("entityName", Identity.Name(uid, EntityManager))), uid, user);
|
||||
_audio.PlayPredicted(lockComp.LockSound, uid, user);
|
||||
_audio.PlayPvs(lockComp.LockSound, uid);
|
||||
|
||||
lockComp.Locked = true;
|
||||
_appearanceSystem.SetData(uid, LockVisuals.Locked, true);
|
||||
@@ -189,7 +186,7 @@ public sealed class LockSystem : EntitySystem
|
||||
("entityName", Identity.Name(uid, EntityManager))), uid, user.Value);
|
||||
}
|
||||
|
||||
_audio.PlayPredicted(lockComp.UnlockSound, uid, user);
|
||||
_audio.PlayPvs(lockComp.UnlockSound, uid);
|
||||
|
||||
lockComp.Locked = false;
|
||||
_appearanceSystem.SetData(uid, LockVisuals.Locked, false);
|
||||
@@ -259,7 +256,12 @@ public sealed class LockSystem : EntitySystem
|
||||
|
||||
var ev = new LockToggleAttemptEvent(user, quiet);
|
||||
RaiseLocalEvent(uid, ref ev, true);
|
||||
return !ev.Cancelled;
|
||||
if (ev.Cancelled)
|
||||
return false;
|
||||
|
||||
var userEv = new UserLockToggleAttemptEvent(uid, quiet);
|
||||
RaiseLocalEvent(user, ref userEv, true);
|
||||
return !userEv.Cancelled;
|
||||
}
|
||||
|
||||
// TODO: this should be a helper on AccessReaderSystem since so many systems copy paste it
|
||||
@@ -304,7 +306,7 @@ public sealed class LockSystem : EntitySystem
|
||||
if (!component.Locked || !component.BreakOnEmag)
|
||||
return;
|
||||
|
||||
_audio.PlayPredicted(component.UnlockSound, uid, args.UserUid);
|
||||
_audio.PlayPvs(component.UnlockSound, uid);
|
||||
|
||||
component.Locked = false;
|
||||
_appearanceSystem.SetData(uid, LockVisuals.Locked, false);
|
||||
@@ -408,4 +410,3 @@ public sealed class LockSystem : EntitySystem
|
||||
_activatableUI.CloseAll(uid);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
18
Content.Shared/Lock/LockingWhitelistComponent.cs
Normal file
18
Content.Shared/Lock/LockingWhitelistComponent.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Lock;
|
||||
|
||||
/// <summary>
|
||||
/// Adds whitelist and blacklist for this mob to lock things.
|
||||
/// The whitelist and blacklist are checked against the object being locked, not the mob.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(LockingWhitelistSystem))]
|
||||
public sealed partial class LockingWhitelistComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public EntityWhitelist? Whitelist;
|
||||
|
||||
[DataField]
|
||||
public EntityWhitelist? Blacklist;
|
||||
}
|
||||
28
Content.Shared/Lock/LockingWhitelistSystem.cs
Normal file
28
Content.Shared/Lock/LockingWhitelistSystem.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Whitelist;
|
||||
|
||||
namespace Content.Shared.Lock;
|
||||
|
||||
public sealed class LockingWhitelistSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<LockingWhitelistComponent, UserLockToggleAttemptEvent>(OnUserLockToggleAttempt);
|
||||
}
|
||||
|
||||
private void OnUserLockToggleAttempt(Entity<LockingWhitelistComponent> ent, ref UserLockToggleAttemptEvent args)
|
||||
{
|
||||
if (_whitelistSystem.CheckBoth(args.Target, ent.Comp.Blacklist, ent.Comp.Whitelist))
|
||||
return;
|
||||
|
||||
if (!args.Silent)
|
||||
_popupSystem.PopupClient(Loc.GetString("locking-whitelist-component-lock-toggle-deny"), ent.Owner);
|
||||
|
||||
args.Cancelled = true;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.Whitelist;
|
||||
using Content.Shared._CP14.ItemPlacerParenting;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Placeable;
|
||||
@@ -7,7 +8,7 @@ namespace Content.Shared.Placeable;
|
||||
/// Detects items placed on it that match a whitelist.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
|
||||
[Access(typeof(ItemPlacerSystem))]
|
||||
[Access(typeof(ItemPlacerSystem), typeof(CP14ItemPlacerAutoParentSystem))]
|
||||
public sealed partial class ItemPlacerComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
namespace Content.Shared.Slippery
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Slippery;
|
||||
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class NoSlipComponent : Component
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed partial class NoSlipComponent : Component
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ public sealed class SwapTeleporterSystem : EntitySystem
|
||||
private void OnInteract(Entity<SwapTeleporterComponent> ent, ref AfterInteractEvent args)
|
||||
{
|
||||
var (uid, comp) = ent;
|
||||
if (args.Target == null)
|
||||
if (args.Target == null || !args.CanReach)
|
||||
return;
|
||||
|
||||
var target = args.Target.Value;
|
||||
|
||||
@@ -15,4 +15,7 @@ public sealed partial class GunRequiresWieldComponent : Component
|
||||
|
||||
[DataField, AutoNetworkedField]
|
||||
public TimeSpan PopupCooldown = TimeSpan.FromSeconds(1);
|
||||
|
||||
[DataField]
|
||||
public LocId? WieldRequiresExamineMessage = "gunrequireswield-component-examine";
|
||||
}
|
||||
|
||||
@@ -23,6 +23,23 @@ public sealed class EntityWhitelistSystem : EntitySystem
|
||||
return uid != null && IsValid(list, uid.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a given entity is allowed by a whitelist and not blocked by a blacklist.
|
||||
/// If a blacklist is provided and it matches then this returns false.
|
||||
/// If a whitelist is provided and it does not match then this returns false.
|
||||
/// If either list is null it does not get checked.
|
||||
/// </summary>
|
||||
public bool CheckBoth([NotNullWhen(true)] EntityUid? uid, EntityWhitelist? blacklist = null, EntityWhitelist? whitelist = null)
|
||||
{
|
||||
if (uid == null)
|
||||
return false;
|
||||
|
||||
if (blacklist != null && IsValid(blacklist, uid))
|
||||
return false;
|
||||
|
||||
return whitelist == null || IsValid(whitelist, uid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks whether a given entity satisfies a whitelist.
|
||||
/// </summary>
|
||||
|
||||
@@ -47,6 +47,7 @@ public sealed class WieldableSystem : EntitySystem
|
||||
SubscribeLocalEvent<WieldableComponent, HandDeselectedEvent>(OnDeselectWieldable);
|
||||
|
||||
SubscribeLocalEvent<MeleeRequiresWieldComponent, AttemptMeleeEvent>(OnMeleeAttempt);
|
||||
SubscribeLocalEvent<GunRequiresWieldComponent, ExaminedEvent>(OnExamineRequires);
|
||||
SubscribeLocalEvent<GunRequiresWieldComponent, ShotAttemptedEvent>(OnShootAttempt);
|
||||
SubscribeLocalEvent<GunWieldBonusComponent, ItemWieldedEvent>(OnGunWielded);
|
||||
SubscribeLocalEvent<GunWieldBonusComponent, ItemUnwieldedEvent>(OnGunUnwielded);
|
||||
@@ -116,8 +117,17 @@ public sealed class WieldableSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
private void OnExamineRequires(Entity<GunRequiresWieldComponent> entity, ref ExaminedEvent args)
|
||||
{
|
||||
if(entity.Comp.WieldRequiresExamineMessage != null)
|
||||
args.PushText(Loc.GetString(entity.Comp.WieldRequiresExamineMessage));
|
||||
}
|
||||
|
||||
private void OnExamine(EntityUid uid, GunWieldBonusComponent component, ref ExaminedEvent args)
|
||||
{
|
||||
if (HasComp<GunRequiresWieldComponent>(uid))
|
||||
return;
|
||||
|
||||
if (component.WieldBonusExamineMessage != null)
|
||||
args.PushText(Loc.GetString(component.WieldBonusExamineMessage));
|
||||
}
|
||||
|
||||
18
Content.Shared/_CP14/Currency/CP14CurrencyComponent.cs
Normal file
18
Content.Shared/_CP14/Currency/CP14CurrencyComponent.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace Content.Shared._CP14.Currency;
|
||||
|
||||
/// <summary>
|
||||
/// Reflects the market value of an item, to guide players through the economy.
|
||||
/// </summary>
|
||||
|
||||
[RegisterComponent, Access(typeof(CP14CurrencySystem))]
|
||||
public sealed partial class CP14CurrencyComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public int Currency = 1;
|
||||
|
||||
/// <summary>
|
||||
/// allows you to categorize different valuable items in order to, for example, give goals for buying weapons, or earning money specifically.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string? Category;
|
||||
}
|
||||
62
Content.Shared/_CP14/Currency/CP14CurrencySystem.cs
Normal file
62
Content.Shared/_CP14/Currency/CP14CurrencySystem.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Stacks;
|
||||
|
||||
namespace Content.Shared._CP14.Currency;
|
||||
|
||||
public sealed partial class CP14CurrencySystem : EntitySystem
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14CurrencyComponent, ExaminedEvent>(OnExamine);
|
||||
}
|
||||
|
||||
private void OnExamine(Entity<CP14CurrencyComponent> currency, ref ExaminedEvent args)
|
||||
{
|
||||
var total = GetTotalCurrency(currency, currency.Comp);
|
||||
|
||||
var push = Loc.GetString("cp14-currency-examine-title");
|
||||
push += GetPrettyCurrency(total);
|
||||
args.PushMarkup(push);
|
||||
}
|
||||
|
||||
public string GetPrettyCurrency(int currency)
|
||||
{
|
||||
var total = currency;
|
||||
|
||||
if (total <= 0)
|
||||
return string.Empty;
|
||||
|
||||
var gp = total / 100;
|
||||
total %= 100;
|
||||
|
||||
var sp = total / 10;
|
||||
total %= 10;
|
||||
|
||||
var cp = total;
|
||||
|
||||
var push = string.Empty;
|
||||
|
||||
if (gp > 0) push += " " + Loc.GetString("cp14-currency-examine-gp", ("coin", gp));
|
||||
if (sp > 0) push += " " + Loc.GetString("cp14-currency-examine-sp", ("coin", sp));
|
||||
if (cp > 0) push += " " + Loc.GetString("cp14-currency-examine-cp", ("coin", cp));
|
||||
|
||||
return push;
|
||||
}
|
||||
|
||||
public int GetTotalCurrency(EntityUid uid, CP14CurrencyComponent? currency = null)
|
||||
{
|
||||
if (!Resolve(uid, ref currency))
|
||||
return 0;
|
||||
|
||||
var total = currency.Currency;
|
||||
|
||||
if (TryComp<StackComponent>(uid, out var stack))
|
||||
{
|
||||
total *= stack.Count;
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Content.Shared._CP14.ItemPlacerParenting;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14ItemPlacerAutoParentSystem))]
|
||||
public sealed partial class CP14ItemPlacerAutoParentComponent : Component
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
using Content.Shared.Movement.Pulling.Events;
|
||||
using Content.Shared.Placeable;
|
||||
using Content.Shared.Tag;
|
||||
using Content.Shared.Throwing;
|
||||
using Robust.Shared.Physics.Events;
|
||||
|
||||
namespace Content.Shared._CP14.ItemPlacerParenting;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public sealed class CP14ItemPlacerAutoParentSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14ItemPlacerAutoParentComponent, ItemPlacedEvent>(OnItemPlaced);
|
||||
SubscribeLocalEvent<CP14ItemPlacerAutoParentComponent, ThrownEvent>(OnThrown);
|
||||
SubscribeLocalEvent<CP14ItemPlacerAutoParentComponent, EndCollideEvent>(OnEndCollide);
|
||||
}
|
||||
|
||||
private void OnEndCollide(Entity<CP14ItemPlacerAutoParentComponent> ent, ref EndCollideEvent args)
|
||||
{
|
||||
if (!TryComp<ItemPlacerComponent>(ent, out var itemPlacer))
|
||||
return;
|
||||
|
||||
Detach(args.OtherEntity, ent);
|
||||
}
|
||||
|
||||
private void Detach(EntityUid item, EntityUid parent)
|
||||
{
|
||||
if (Transform(item).ParentUid == parent)
|
||||
_transform.SetParent(item, Transform(parent).ParentUid);
|
||||
}
|
||||
|
||||
private void OnThrown(Entity<CP14ItemPlacerAutoParentComponent> ent, ref ThrownEvent args)
|
||||
{
|
||||
if (!TryComp<ItemPlacerComponent>(ent, out var itemPlacer))
|
||||
return;
|
||||
|
||||
foreach (var placed in itemPlacer.PlacedEntities)
|
||||
{
|
||||
Detach(placed, ent);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnItemPlaced(Entity<CP14ItemPlacerAutoParentComponent> ent, ref ItemPlacedEvent args)
|
||||
{
|
||||
if (HasComp<CP14ItemPlacerParentedComponent>(ent))
|
||||
return;
|
||||
|
||||
if (!TryComp<ItemPlacerComponent>(ent, out var itemPlacer))
|
||||
return;
|
||||
|
||||
_transform.SetParent(args.OtherEntity, ent);
|
||||
AddComp<CP14ItemPlacerParentedComponent>(ent);
|
||||
}
|
||||
|
||||
private void Detach(EntityUid target)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace Content.Shared._CP14.ItemPlacerParenting;
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14ItemPlacerAutoParentSystem))]
|
||||
public sealed partial class CP14ItemPlacerParentedComponent : Component
|
||||
{
|
||||
}
|
||||
@@ -28,7 +28,6 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
|
||||
|
||||
private const int DepthComplexity = 2; //TODO - fix this constant duplication from KeyholeGenerationSystem.cs
|
||||
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -54,7 +53,6 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
|
||||
if (!TryComp<StorageComponent>(keyring, out var storageComp))
|
||||
return;
|
||||
|
||||
|
||||
if (TryComp<LockComponent>(args.Target, out var lockComp) &&
|
||||
TryGetLockFromSlot(args.Target.Value, out var lockEnt))
|
||||
{
|
||||
@@ -71,7 +69,7 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
|
||||
args.Handled = true;
|
||||
return;
|
||||
}
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-keyring-use-nofit"), args.Target.Value, args.User);
|
||||
_popup.PopupEntity(Loc.GetString("cp14-lock-keyring-use-nofit"), args.Target.Value, args.User);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,10 +115,11 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
|
||||
{
|
||||
TryHackDoorElement(user, target, lockpick, lockItemComp, lockComp, height);
|
||||
},
|
||||
Text = Loc.GetString("cp-lock-verb-lockpick-use-text") + $" {height}",
|
||||
Message = Loc.GetString("cp-lock-verb-lockpick-use-message"),
|
||||
Text = Loc.GetString("cp14-lock-verb-lockpick-use-text") + $" {height}",
|
||||
Message = Loc.GetString("cp14-lock-verb-lockpick-use-message"),
|
||||
Category = VerbCategory.Lockpick,
|
||||
Priority = height,
|
||||
CloseMenu = false,
|
||||
};
|
||||
|
||||
args.Verbs.Add(verb);
|
||||
@@ -141,19 +140,19 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
|
||||
if (lockComp.Locked)
|
||||
{
|
||||
_lock.TryUnlock(target, user, lockComp);
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-unlock-lock", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
|
||||
_popup.PopupEntity(Loc.GetString("cp14-lock-unlock-lock", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
|
||||
lockEnt.LockpickStatus = 0;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lock.TryLock(target, user, lockComp);
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-lock-lock", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
|
||||
_popup.PopupEntity(Loc.GetString("cp14-lock-lock-lock", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
|
||||
lockEnt.LockpickStatus = 0;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-lockpick-success"), target, user);
|
||||
_popup.PopupEntity(Loc.GetString("cp14-lock-lockpick-success"), target, user);
|
||||
return true;
|
||||
}
|
||||
else //Fail
|
||||
@@ -164,16 +163,16 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
|
||||
lockpick.Comp.Health--;
|
||||
if (lockpick.Comp.Health > 0)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-lockpick-failed-damage", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
|
||||
_popup.PopupEntity(Loc.GetString("cp14-lock-lockpick-failed-damage", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
|
||||
} else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-lockpick-failed-break", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
|
||||
_popup.PopupEntity(Loc.GetString("cp14-lock-lockpick-failed-break", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
|
||||
QueueDel(lockpick);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-lockpick-failed", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
|
||||
_popup.PopupEntity(Loc.GetString("cp14-lock-lockpick-failed", ("lock", MetaData(lockEnt.Owner).EntityName)), target, user);
|
||||
}
|
||||
lockEnt.LockpickeddFailMarkup = true;
|
||||
lockEnt.LockpickStatus = 0;
|
||||
@@ -205,8 +204,8 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
|
||||
TryUseKeyOnLock(user, target, key, new Entity<CP14LockComponent>(target, lockItemComp));
|
||||
},
|
||||
IconEntity = GetNetEntity(key),
|
||||
Text = Loc.GetString(lockComp.Locked ? "cp-lock-verb-use-key-text-open" : "cp-lock-verb-use-key-text-close", ("item", MetaData(args.Target).EntityName)),
|
||||
Message = Loc.GetString("cp-lock-verb-use-key-message", ("item", MetaData(args.Target).EntityName))
|
||||
Text = Loc.GetString(lockComp.Locked ? "cp14-lock-verb-use-key-text-open" : "cp14-lock-verb-use-key-text-close", ("item", MetaData(args.Target).EntityName)),
|
||||
Message = Loc.GetString("cp14-lock-verb-use-key-message", ("item", MetaData(args.Target).EntityName)),
|
||||
};
|
||||
|
||||
args.Verbs.Add(verb);
|
||||
@@ -220,14 +219,10 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
|
||||
if (args.Container.ID != lockSlot.Comp.LockSlotId)
|
||||
return;
|
||||
|
||||
if (!TryComp<CP14LockComponent>(args.EntityUid, out var lockComp))
|
||||
{
|
||||
args.Cancel();
|
||||
if (TryComp<CP14LockComponent>(args.EntityUid, out var lockComp))
|
||||
return;
|
||||
}
|
||||
|
||||
if (lockComp == null)
|
||||
return;
|
||||
args.Cancel();
|
||||
|
||||
//if (lockComp.Locked)
|
||||
//{
|
||||
@@ -309,18 +304,18 @@ public sealed class SharedCP14LockKeySystem : EntitySystem
|
||||
if (lockComp.Locked)
|
||||
{
|
||||
if(_lock.TryUnlock(target, user))
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-unlock-lock", ("lock", MetaData(lockEnt).EntityName)), lockEnt, user);
|
||||
_popup.PopupEntity(Loc.GetString("cp14-lock-unlock-lock", ("lock", MetaData(lockEnt).EntityName)), lockEnt, user);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_lock.TryLock(target, user))
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-lock-lock", ("lock", MetaData(lockEnt).EntityName)), lockEnt, user);
|
||||
_popup.PopupEntity(Loc.GetString("cp14-lock-lock-lock", ("lock", MetaData(lockEnt).EntityName)), lockEnt, user);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cp-lock-key-use-nofit"), lockEnt, user);
|
||||
_popup.PopupEntity(Loc.GetString("cp14-lock-key-use-nofit"), lockEnt, user);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
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;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
namespace Content.Shared._CP14.MagicAttuning;
|
||||
|
||||
/// <summary>
|
||||
/// A mind that can focus on objects
|
||||
/// </summary>
|
||||
[RegisterComponent, 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;
|
||||
}
|
||||
@@ -0,0 +1,238 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.MagicEnergy.Components;
|
||||
|
||||
@@ -13,4 +15,7 @@ public sealed partial class CP14MagicEnergyContainerComponent : Component
|
||||
|
||||
[DataField]
|
||||
public FixedPoint2 MaxEnergy = 100f;
|
||||
|
||||
[DataField]
|
||||
public ProtoId<AlertPrototype>? MagicAlert = null;
|
||||
}
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
using Content.Shared.Inventory;
|
||||
|
||||
namespace Content.Shared._CP14.MagicEnergy.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Controls the strength of the PointLight component, depending on the amount of mana in the object
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(SharedCP14MagicEnergySystem))]
|
||||
public sealed partial class CP14MagicEnergyPointLightControllerComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public float MaxEnergy = 1f;
|
||||
|
||||
[DataField]
|
||||
public float MinEnergy = 0f;
|
||||
}
|
||||
@@ -1,15 +1,37 @@
|
||||
using Content.Shared._CP14.MagicEnergy.Components;
|
||||
using Content.Shared.Examine;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Rounding;
|
||||
|
||||
namespace Content.Shared._CP14.MagicEnergy;
|
||||
|
||||
public partial class SharedCP14MagicEnergySystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly AlertsSystem _alerts = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<CP14MagicEnergyContainerComponent, ComponentStartup>(OnComponentStartup);
|
||||
SubscribeLocalEvent<CP14MagicEnergyContainerComponent, ComponentShutdown>(OnComponentShutdown);
|
||||
}
|
||||
|
||||
private void OnComponentStartup(Entity<CP14MagicEnergyContainerComponent> ent, ref ComponentStartup args)
|
||||
{
|
||||
UpdateMagicAlert(ent);
|
||||
}
|
||||
|
||||
private void OnComponentShutdown(Entity<CP14MagicEnergyContainerComponent> ent, ref ComponentShutdown args)
|
||||
{
|
||||
if (ent.Comp.MagicAlert == null)
|
||||
return;
|
||||
|
||||
_alerts.ClearAlert(ent, ent.Comp.MagicAlert.Value);
|
||||
}
|
||||
|
||||
public string GetEnergyExaminedText(EntityUid uid, CP14MagicEnergyContainerComponent ent)
|
||||
{
|
||||
var power = (int)((ent.Energy / ent.MaxEnergy) * 100);
|
||||
var power = (int)(ent.Energy / ent.MaxEnergy * 100);
|
||||
|
||||
var color = "#3fc488";
|
||||
if (power < 66)
|
||||
@@ -22,6 +44,92 @@ public partial class SharedCP14MagicEnergySystem : EntitySystem
|
||||
("power", power),
|
||||
("color", color));
|
||||
}
|
||||
|
||||
public void ChangeEnergy(EntityUid uid, CP14MagicEnergyContainerComponent component, FixedPoint2 energy, bool safe = false)
|
||||
{
|
||||
if (!safe)
|
||||
{
|
||||
//Overload
|
||||
if (component.Energy + energy > component.MaxEnergy)
|
||||
{
|
||||
RaiseLocalEvent(uid, new CP14MagicEnergyOverloadEvent()
|
||||
{
|
||||
OverloadEnergy = (component.Energy + energy) - component.MaxEnergy,
|
||||
});
|
||||
}
|
||||
|
||||
//Burn out
|
||||
if (component.Energy + energy < 0)
|
||||
{
|
||||
RaiseLocalEvent(uid, new CP14MagicEnergyBurnOutEvent()
|
||||
{
|
||||
BurnOutEnergy = -energy - component.Energy
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var oldEnergy = component.Energy;
|
||||
var newEnergy = Math.Clamp((float)component.Energy + (float)energy, 0, (float)component.MaxEnergy);
|
||||
component.Energy = newEnergy;
|
||||
|
||||
if (oldEnergy != newEnergy)
|
||||
{
|
||||
RaiseLocalEvent(uid, new CP14MagicEnergyLevelChangeEvent()
|
||||
{
|
||||
OldValue = component.Energy,
|
||||
NewValue = newEnergy,
|
||||
MaxValue = component.MaxEnergy,
|
||||
});
|
||||
}
|
||||
|
||||
UpdateMagicAlert((uid, component));
|
||||
}
|
||||
|
||||
public bool HasEnergy(EntityUid uid, FixedPoint2 energy, CP14MagicEnergyContainerComponent? component = null, bool safe = false)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
|
||||
if (safe == false)
|
||||
return true;
|
||||
|
||||
return component.Energy > energy;
|
||||
}
|
||||
|
||||
public bool TryConsumeEnergy(EntityUid uid, FixedPoint2 energy, CP14MagicEnergyContainerComponent? component = null, bool safe = false)
|
||||
{
|
||||
if (!Resolve(uid, ref component))
|
||||
return false;
|
||||
|
||||
if (energy <= 0)
|
||||
return true;
|
||||
|
||||
// Attempting to absorb more energy than is contained in the container available only in non-safe methods (with container destruction)
|
||||
if (component.Energy < energy)
|
||||
{
|
||||
if (safe)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
ChangeEnergy(uid, component, -energy, safe);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ChangeEnergy(uid, component, -energy, safe);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void UpdateMagicAlert(Entity<CP14MagicEnergyContainerComponent> ent)
|
||||
{
|
||||
if (ent.Comp.MagicAlert == null)
|
||||
return;
|
||||
|
||||
var level = ContentHelpers.RoundToLevels(MathF.Max(0f, (float) ent.Comp.Energy), (float) ent.Comp.MaxEnergy, 10);
|
||||
_alerts.ShowAlert(ent, ent.Comp.MagicAlert.Value, (short)level);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
317
Content.Shared/_CP14/MagicSpell/CP14SharedMagicSystem.cs
Normal file
317
Content.Shared/_CP14/MagicSpell/CP14SharedMagicSystem.cs
Normal file
@@ -0,0 +1,317 @@
|
||||
using Content.Shared._CP14.MagicEnergy;
|
||||
using Content.Shared._CP14.MagicEnergy.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Components;
|
||||
using Content.Shared._CP14.MagicSpell.Events;
|
||||
using Content.Shared._CP14.MagicSpell.Spells;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Popups;
|
||||
using Content.Shared.Speech.Muting;
|
||||
using Content.Shared.Weapons.Ranged.Systems;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Network;
|
||||
using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell;
|
||||
|
||||
/// <summary>
|
||||
/// This system handles the basic mechanics of spell use, such as doAfter, event invocation, and energy spending.
|
||||
/// </summary>
|
||||
public partial class CP14SharedMagicSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
|
||||
[Dependency] private readonly INetManager _net = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly IMapManager _mapManager = default!;
|
||||
[Dependency] private readonly SharedGunSystem _gunSystem = default!;
|
||||
[Dependency] private readonly SharedCP14MagicEnergySystem _magicEnergy = default!;
|
||||
[Dependency] private readonly SharedPopupSystem _popup = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14BeforeCastMagicEffectEvent>(OnBeforeCastMagicEffect);
|
||||
|
||||
SubscribeLocalEvent<CP14DelayedInstantActionEvent>(OnInstantAction);
|
||||
SubscribeLocalEvent<CP14DelayedEntityTargetActionEvent>(OnEntityTargetAction);
|
||||
SubscribeLocalEvent<CP14DelayedWorldTargetActionEvent>(OnWorldTargetAction);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14DelayedInstantActionDoAfterEvent>(OnDelayedInstantActionDoAfter);
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14DelayedEntityTargetActionDoAfterEvent>(OnDelayedEntityTargetDoAfter);
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14DelayedWorldTargetActionDoAfterEvent>(OnDelayedWorldTargetDoAfter);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectSomaticAspectComponent, CP14BeforeCastMagicEffectEvent>(OnSomaticAspectBeforeCast);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14BeforeCastMagicEffectEvent>(OnVerbalAspectBeforeCast);
|
||||
SubscribeLocalEvent<CP14MagicEffectVerbalAspectComponent, CP14AfterCastMagicEffectEvent>(OnVerbalAspectAfterCast);
|
||||
|
||||
SubscribeLocalEvent<CP14MagicEffectComponent, CP14AfterCastMagicEffectEvent>(OnAfterCastMagicEffect);
|
||||
|
||||
}
|
||||
|
||||
private void OnBeforeCastMagicEffect(Entity<CP14MagicEffectComponent> ent, ref CP14BeforeCastMagicEffectEvent args)
|
||||
{
|
||||
if (!TryComp<CP14MagicEnergyContainerComponent>(args.Performer, out var magicContainer))
|
||||
{
|
||||
args.Cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_magicEnergy.HasEnergy(args.Performer, ent.Comp.ManaCost, magicContainer, ent.Comp.Safe))
|
||||
{
|
||||
args.PushReason(Loc.GetString("cp14-magic-spell-not-enough-mana"));
|
||||
args.Cancel();
|
||||
}
|
||||
else if(!_magicEnergy.HasEnergy(args.Performer, ent.Comp.ManaCost, magicContainer, true) && _net.IsServer)
|
||||
{
|
||||
_popup.PopupEntity(Loc.GetString("cp14-magic-spell-not-enough-mana-cast-warning-"+_random.Next(5)), args.Performer, args.Performer, PopupType.SmallCaution);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnInstantAction(CP14DelayedInstantActionEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
|
||||
if (args is not ICP14DelayedMagicEffect delayedEffect)
|
||||
return;
|
||||
|
||||
if (!TryCastSpell(args.Action, args.Performer))
|
||||
return;
|
||||
|
||||
var doAfterEventArgs = new DoAfterArgs(EntityManager, args.Performer, delayedEffect.Delay, new CP14DelayedInstantActionDoAfterEvent(), args.Action)
|
||||
{
|
||||
BreakOnMove = delayedEffect.BreakOnMove,
|
||||
BreakOnDamage = delayedEffect.BreakOnDamage,
|
||||
Hidden = delayedEffect.Hidden,
|
||||
BlockDuplicate = true,
|
||||
DistanceThreshold = 100f,
|
||||
};
|
||||
|
||||
_doAfter.TryStartDoAfter(doAfterEventArgs);
|
||||
|
||||
//Telegraphy effects
|
||||
if (_net.IsServer && TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
|
||||
{
|
||||
foreach (var effect in magicEffect.TelegraphyEffects)
|
||||
{
|
||||
effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.Performer, args.Performer, Transform(args.Performer).Coordinates));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWorldTargetAction(CP14DelayedWorldTargetActionEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
|
||||
if (args is not ICP14DelayedMagicEffect delayedEffect)
|
||||
return;
|
||||
|
||||
if (!TryCastSpell(args.Action, args.Performer))
|
||||
return;
|
||||
|
||||
var doAfter = new CP14DelayedWorldTargetActionDoAfterEvent()
|
||||
{
|
||||
Target = EntityManager.GetNetCoordinates(args.Target)
|
||||
};
|
||||
|
||||
var doAfterEventArgs = new DoAfterArgs(EntityManager, args.Performer, delayedEffect.Delay, doAfter, args.Action)
|
||||
{
|
||||
BreakOnMove = delayedEffect.BreakOnMove,
|
||||
BreakOnDamage = delayedEffect.BreakOnDamage,
|
||||
Hidden = delayedEffect.Hidden,
|
||||
BlockDuplicate = true,
|
||||
DistanceThreshold = 100f,
|
||||
};
|
||||
|
||||
_doAfter.TryStartDoAfter(doAfterEventArgs);
|
||||
|
||||
//Telegraphy effects
|
||||
if (_net.IsServer && TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
|
||||
{
|
||||
foreach (var effect in magicEffect.TelegraphyEffects)
|
||||
{
|
||||
effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.Performer, null, args.Target));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEntityTargetAction(CP14DelayedEntityTargetActionEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
|
||||
if (args is not ICP14DelayedMagicEffect delayedEffect)
|
||||
return;
|
||||
|
||||
if (!TryCastSpell(args.Action, args.Performer))
|
||||
return;
|
||||
|
||||
var doAfterEventArgs = new DoAfterArgs(EntityManager, args.Performer, delayedEffect.Delay, new CP14DelayedEntityTargetActionDoAfterEvent(), args.Action, args.Target)
|
||||
{
|
||||
BreakOnMove = delayedEffect.BreakOnMove,
|
||||
BreakOnDamage = delayedEffect.BreakOnDamage,
|
||||
Hidden = delayedEffect.Hidden,
|
||||
BlockDuplicate = true,
|
||||
DistanceThreshold = 100f,
|
||||
};
|
||||
|
||||
_doAfter.TryStartDoAfter(doAfterEventArgs);
|
||||
|
||||
//Telegraphy effects
|
||||
if (_net.IsServer && TryComp<CP14MagicEffectComponent>(args.Action, out var magicEffect))
|
||||
{
|
||||
foreach (var effect in magicEffect.TelegraphyEffects)
|
||||
{
|
||||
effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.Performer, args.Target, null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDelayedWorldTargetDoAfter(Entity<CP14MagicEffectComponent> ent, ref CP14DelayedWorldTargetActionDoAfterEvent args)
|
||||
{
|
||||
var endEv = new CP14EndCastMagicEffectEvent();
|
||||
RaiseLocalEvent(ent, ref endEv);
|
||||
|
||||
if (args.Cancelled || !_net.IsServer)
|
||||
return;
|
||||
|
||||
foreach (var effect in ent.Comp.Effects)
|
||||
{
|
||||
effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.User, null, GetCoordinates(args.Target)));
|
||||
}
|
||||
|
||||
var ev = new CP14AfterCastMagicEffectEvent {Performer = args.User};
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
|
||||
private void OnDelayedEntityTargetDoAfter(Entity<CP14MagicEffectComponent> ent, ref CP14DelayedEntityTargetActionDoAfterEvent args)
|
||||
{
|
||||
var endEv = new CP14EndCastMagicEffectEvent();
|
||||
RaiseLocalEvent(ent, ref endEv);
|
||||
|
||||
if (args.Cancelled || !_net.IsServer)
|
||||
return;
|
||||
|
||||
foreach (var effect in ent.Comp.Effects)
|
||||
{
|
||||
effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.User, args.Target, null));
|
||||
}
|
||||
|
||||
var ev = new CP14AfterCastMagicEffectEvent {Performer = args.User};
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
|
||||
private void OnDelayedInstantActionDoAfter(Entity<CP14MagicEffectComponent> ent, ref CP14DelayedInstantActionDoAfterEvent args)
|
||||
{
|
||||
var endEv = new CP14EndCastMagicEffectEvent();
|
||||
RaiseLocalEvent(ent, ref endEv);
|
||||
|
||||
if (args.Cancelled || !_net.IsServer)
|
||||
return;
|
||||
|
||||
foreach (var effect in ent.Comp.Effects)
|
||||
{
|
||||
effect.Effect(EntityManager, new CP14SpellEffectBaseArgs(args.User, args.User, Transform(args.User).Coordinates));
|
||||
}
|
||||
|
||||
var ev = new CP14AfterCastMagicEffectEvent {Performer = args.User};
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
|
||||
private void OnSomaticAspectBeforeCast(Entity<CP14MagicEffectSomaticAspectComponent> ent, ref CP14BeforeCastMagicEffectEvent args)
|
||||
{
|
||||
if (TryComp<HandsComponent>(args.Performer, out var hands) || hands is not null)
|
||||
{
|
||||
var freeHand = 0;
|
||||
foreach (var hand in hands.Hands)
|
||||
{
|
||||
if (hand.Value.IsEmpty)
|
||||
freeHand++;
|
||||
}
|
||||
if (freeHand >= ent.Comp.FreeHandRequired)
|
||||
return;
|
||||
}
|
||||
args.PushReason(Loc.GetString("cp14-magic-spell-need-somatic-component"));
|
||||
args.Cancel();
|
||||
}
|
||||
|
||||
private void OnVerbalAspectBeforeCast(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14BeforeCastMagicEffectEvent args)
|
||||
{
|
||||
if (HasComp<MutedComponent>(args.Performer))
|
||||
{
|
||||
args.PushReason(Loc.GetString("cp14-magic-spell-need-verbal-component"));
|
||||
args.Cancel();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!args.Cancelled)
|
||||
{
|
||||
var ev = new CP14VerbalAspectSpeechEvent
|
||||
{
|
||||
Performer = args.Performer,
|
||||
Speech = ent.Comp.StartSpeech,
|
||||
};
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnVerbalAspectAfterCast(Entity<CP14MagicEffectVerbalAspectComponent> ent, ref CP14AfterCastMagicEffectEvent args)
|
||||
{
|
||||
if (_net.IsClient)
|
||||
return;
|
||||
|
||||
var ev = new CP14VerbalAspectSpeechEvent
|
||||
{
|
||||
Performer = args.Performer,
|
||||
Speech = ent.Comp.EndSpeech,
|
||||
};
|
||||
RaiseLocalEvent(ent, ref ev);
|
||||
}
|
||||
|
||||
private bool TryCastSpell(EntityUid spell, EntityUid performer)
|
||||
{
|
||||
var ev = new CP14BeforeCastMagicEffectEvent
|
||||
{
|
||||
Performer = performer,
|
||||
};
|
||||
RaiseLocalEvent(spell, ref ev);
|
||||
if (ev.Reason != string.Empty && _net.IsServer)
|
||||
{
|
||||
_popup.PopupEntity(ev.Reason, performer, performer);
|
||||
}
|
||||
|
||||
if (!ev.Cancelled)
|
||||
{
|
||||
var evStart = new CP14StartCastMagicEffectEvent()
|
||||
{
|
||||
Performer = performer,
|
||||
};
|
||||
RaiseLocalEvent(spell, ref evStart);
|
||||
}
|
||||
return !ev.Cancelled;
|
||||
}
|
||||
|
||||
private void OnAfterCastMagicEffect(Entity<CP14MagicEffectComponent> ent, ref CP14AfterCastMagicEffectEvent args)
|
||||
{
|
||||
if (_net.IsClient)
|
||||
return;
|
||||
|
||||
if (!HasComp<CP14MagicEnergyContainerComponent>(args.Performer))
|
||||
return;
|
||||
|
||||
_magicEnergy.TryConsumeEnergy(args.Performer.Value, ent.Comp.ManaCost, safe: ent.Comp.Safe);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a temporary entity that exists while the spell is cast, and disappears at the end. For visual special effects.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14MagicEffectCastingVisualComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public EntityUid? SpawnedEntity;
|
||||
|
||||
[DataField(required: true)]
|
||||
public EntProtoId Proto = default!;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using Content.Shared._CP14.MagicSpell.Spells;
|
||||
using Content.Shared.FixedPoint;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Restricts the use of this action, by spending mana or user requirements.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14MagicEffectComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public FixedPoint2 ManaCost = 0f;
|
||||
|
||||
[DataField]
|
||||
public bool Safe = false;
|
||||
|
||||
/// <summary>
|
||||
/// Effects that will trigger at the beginning of the cast, before mana is spent. Should have no gameplay importance, just special effects, popups and sounds.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public List<CP14SpellEffect> TelegraphyEffects = new();
|
||||
|
||||
[DataField]
|
||||
public List<CP14SpellEffect> Effects = new();
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Content.Shared._CP14.MagicSpell.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Requires the user to have at least one free hand to use this spell
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14MagicEffectSomaticAspectComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public int FreeHandRequired = 1;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
namespace Content.Shared._CP14.MagicSpell.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Requires the user to be able to speak in order to use this spell. Also forces the user to use certain phrases at the beginning and end of a spell cast
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(CP14SharedMagicSystem))]
|
||||
public sealed partial class CP14MagicEffectVerbalAspectComponent : Component
|
||||
{
|
||||
[DataField]
|
||||
public string StartSpeech = string.Empty;
|
||||
|
||||
[DataField]
|
||||
public string EndSpeech = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// patch to send an event to the server for saying a phrase out loud
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public sealed class CP14VerbalAspectSpeechEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid? Performer { get; init; }
|
||||
|
||||
public string? Speech { get; init; }
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
namespace Content.Shared._CP14.MagicSpell.Events;
|
||||
|
||||
[ByRefEvent]
|
||||
public sealed class CP14BeforeCastMagicEffectEvent : CancellableEntityEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// The Performer of the event, to check if they meet the requirements.
|
||||
/// </summary>
|
||||
public EntityUid Performer { get; init; }
|
||||
|
||||
public string Reason = string.Empty;
|
||||
|
||||
public void PushReason(string reason)
|
||||
{
|
||||
Reason += $"{reason}\n";
|
||||
}
|
||||
}
|
||||
|
||||
[ByRefEvent]
|
||||
public sealed class CP14AfterCastMagicEffectEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid? Performer { get; init; }
|
||||
}
|
||||
/// <summary>
|
||||
/// is invoked if all conditions are met and the spell has begun to be cast
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public sealed class CP14StartCastMagicEffectEvent : EntityEventArgs
|
||||
{
|
||||
public EntityUid Performer { get; init; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// is invoked on the spell itself when the spell process has been completed or interrupted
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public sealed class CP14EndCastMagicEffectEvent : EntityEventArgs
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
using Content.Shared.Actions;
|
||||
using Content.Shared.DoAfter;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared._CP14.MagicSpell.Events;
|
||||
|
||||
//World target
|
||||
public sealed partial class CP14DelayedWorldTargetActionEvent : WorldTargetActionEvent, ICP14DelayedMagicEffect
|
||||
{
|
||||
[DataField]
|
||||
public float Delay { get; private set; } = 1f;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnMove { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnDamage { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public bool Hidden { get; private set; } = false;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CP14DelayedWorldTargetActionDoAfterEvent : DoAfterEvent
|
||||
{
|
||||
[DataField]
|
||||
public NetCoordinates Target;
|
||||
public override DoAfterEvent Clone() => this;
|
||||
}
|
||||
|
||||
|
||||
//Entity Target
|
||||
public sealed partial class CP14DelayedEntityTargetActionEvent : EntityTargetActionEvent, ICP14DelayedMagicEffect
|
||||
{
|
||||
[DataField]
|
||||
public float Delay { get; private set; } = 1f;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnMove { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnDamage { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public bool Hidden { get; private set; } = false;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CP14DelayedEntityTargetActionDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
}
|
||||
|
||||
//Instant
|
||||
public sealed partial class CP14DelayedInstantActionEvent : InstantActionEvent, ICP14DelayedMagicEffect
|
||||
{
|
||||
[DataField]
|
||||
public float Delay { get; private set; } = 1f;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnMove { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public bool BreakOnDamage { get; private set; } = true;
|
||||
|
||||
[DataField]
|
||||
public bool Hidden { get; private set; } = false;
|
||||
}
|
||||
|
||||
[Serializable, NetSerializable]
|
||||
public sealed partial class CP14DelayedInstantActionDoAfterEvent : SimpleDoAfterEvent
|
||||
{
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user