Merge branch 'master' into buckle-locker-fix-1262

This commit is contained in:
DrSmugleaf
2020-07-08 15:35:20 +02:00
121 changed files with 1116 additions and 772 deletions

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using Content.Shared.Chat; using Content.Shared.Chat;
using Robust.Client.Console;
using Robust.Client.Graphics.Drawing; using Robust.Client.Graphics.Drawing;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
@@ -26,6 +27,7 @@ namespace Content.Client.Chat
public Button AllButton { get; } public Button AllButton { get; }
public Button LocalButton { get; } public Button LocalButton { get; }
public Button OOCButton { get; } public Button OOCButton { get; }
public Button AdminButton { get; }
/// <summary> /// <summary>
/// Default formatting string for the ClientChatConsole. /// Default formatting string for the ClientChatConsole.
@@ -59,6 +61,7 @@ namespace Content.Client.Chat
outerVBox.AddChild(panelContainer); outerVBox.AddChild(panelContainer);
outerVBox.AddChild(hBox); outerVBox.AddChild(hBox);
var contentMargin = new MarginContainer var contentMargin = new MarginContainer
{ {
MarginLeftOverride = 4, MarginRightOverride = 4, MarginLeftOverride = 4, MarginRightOverride = 4,
@@ -95,6 +98,17 @@ namespace Content.Client.Chat
ToggleMode = true, ToggleMode = true,
}; };
var groupController = IoCManager.Resolve<IClientConGroupController>();
if(groupController.CanCommand("asay"))
{
AdminButton = new Button
{
Text = _localize.GetString("Admin"),
Name = "Admin",
ToggleMode = true,
};
}
AllButton.OnToggled += OnFilterToggled; AllButton.OnToggled += OnFilterToggled;
LocalButton.OnToggled += OnFilterToggled; LocalButton.OnToggled += OnFilterToggled;
OOCButton.OnToggled += OnFilterToggled; OOCButton.OnToggled += OnFilterToggled;
@@ -102,6 +116,11 @@ namespace Content.Client.Chat
hBox.AddChild(AllButton); hBox.AddChild(AllButton);
hBox.AddChild(LocalButton); hBox.AddChild(LocalButton);
hBox.AddChild(OOCButton); hBox.AddChild(OOCButton);
if(AdminButton != null)
{
AdminButton.OnToggled += OnFilterToggled;
hBox.AddChild(AdminButton);
}
AddChild(outerVBox); AddChild(outerVBox);
} }

View File

@@ -48,6 +48,7 @@ namespace Content.Client.Chat
private const char ConCmdSlash = '/'; private const char ConCmdSlash = '/';
private const char OOCAlias = '['; private const char OOCAlias = '[';
private const char MeAlias = '@'; private const char MeAlias = '@';
private const char AdminChatAlias = ']';
private readonly List<StoredChatMessage> filteredHistory = new List<StoredChatMessage>(); private readonly List<StoredChatMessage> filteredHistory = new List<StoredChatMessage>();
@@ -55,6 +56,7 @@ namespace Content.Client.Chat
private bool _allState; private bool _allState;
private bool _localState; private bool _localState;
private bool _oocState; private bool _oocState;
private bool _adminState;
// Flag Enums for holding filtered channels // Flag Enums for holding filtered channels
private ChatChannel _filteredChannels; private ChatChannel _filteredChannels;
@@ -65,6 +67,7 @@ namespace Content.Client.Chat
[Dependency] private readonly IEntityManager _entityManager; [Dependency] private readonly IEntityManager _entityManager;
[Dependency] private readonly IEyeManager _eyeManager; [Dependency] private readonly IEyeManager _eyeManager;
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager; [Dependency] private readonly IUserInterfaceManager _userInterfaceManager;
[Dependency] private readonly IClientConGroupController _groupController = default!;
#pragma warning restore 649 #pragma warning restore 649
private ChatBox _currentChatBox; private ChatBox _currentChatBox;
@@ -150,6 +153,8 @@ namespace Content.Client.Chat
_currentChatBox.AllButton.Pressed = !_allState; _currentChatBox.AllButton.Pressed = !_allState;
_currentChatBox.LocalButton.Pressed = !_localState; _currentChatBox.LocalButton.Pressed = !_localState;
_currentChatBox.OOCButton.Pressed = !_oocState; _currentChatBox.OOCButton.Pressed = !_oocState;
if(chatBox.AdminButton != null)
_currentChatBox.AdminButton.Pressed = !_adminState;
} }
public void RemoveSpeechBubble(EntityUid entityUid, SpeechBubble bubble) public void RemoveSpeechBubble(EntityUid entityUid, SpeechBubble bubble)
@@ -193,6 +198,9 @@ namespace Content.Client.Chat
case ChatChannel.Dead: case ChatChannel.Dead:
color = Color.MediumPurple; color = Color.MediumPurple;
break; break;
case ChatChannel.AdminChat:
color = Color.Red;
break;
} }
_currentChatBox?.AddLine(messageText, message.Channel, color); _currentChatBox?.AddLine(messageText, message.Channel, color);
@@ -220,6 +228,18 @@ namespace Content.Client.Chat
_console.ProcessCommand($"ooc \"{CommandParsing.Escape(conInput)}\""); _console.ProcessCommand($"ooc \"{CommandParsing.Escape(conInput)}\"");
break; break;
} }
case AdminChatAlias:
{
var conInput = text.Substring(1);
if(_groupController.CanCommand("asay")){
_console.ProcessCommand($"asay \"{CommandParsing.Escape(conInput)}\"");
}
else
{
_console.ProcessCommand($"ooc \"{CommandParsing.Escape(conInput)}\"");
}
break;
}
case MeAlias: case MeAlias:
{ {
var conInput = text.Substring(1); var conInput = text.Substring(1);
@@ -266,10 +286,23 @@ namespace Content.Client.Chat
_filteredChannels &= ~ChatChannel.OOC; _filteredChannels &= ~ChatChannel.OOC;
break; break;
} }
case "Admin":
_adminState = !_adminState;
if (_adminState)
{
_filteredChannels |= ChatChannel.AdminChat;
break;
}
else
{
_filteredChannels &= ~ChatChannel.AdminChat;
break;
}
case "ALL": case "ALL":
chatBox.LocalButton.Pressed ^= true; chatBox.LocalButton.Pressed ^= true;
chatBox.OOCButton.Pressed ^= true; chatBox.OOCButton.Pressed ^= true;
chatBox.AdminButton.Pressed ^= true;
_allState = !_allState; _allState = !_allState;
break; break;
} }

View File

@@ -1,3 +1,4 @@
#nullable enable
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text; using System.Text;
@@ -11,8 +12,6 @@ using Robust.Shared.ViewVariables;
using SixLabors.ImageSharp; using SixLabors.ImageSharp;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
#nullable enable
namespace Content.Client namespace Content.Client
{ {
internal class ClickMapManager : IClickMapManager, IPostInjectInit internal class ClickMapManager : IClickMapManager, IPostInjectInit

View File

@@ -1,3 +1,4 @@
#nullable enable
using System; using System;
using Robust.Client.Graphics.ClientEye; using Robust.Client.Graphics.ClientEye;
using Robust.Client.Interfaces.GameObjects.Components; using Robust.Client.Interfaces.GameObjects.Components;
@@ -8,8 +9,6 @@ using Robust.Shared.Maths;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
#nullable enable
namespace Content.Client.GameObjects.Components namespace Content.Client.GameObjects.Components
{ {
[RegisterComponent] [RegisterComponent]

View File

@@ -1,24 +1,17 @@
#nullable enable
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Content.Shared.GameObjects.Components.Instruments; using Content.Shared.GameObjects.Components.Instruments;
using Content.Shared.Physics; using Content.Shared.Physics;
using JetBrains.Annotations;
using NFluidsynth;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Client.Audio.Midi; using Robust.Client.Audio.Midi;
using Robust.Client.Player;
using Robust.Shared.Interfaces.Log;
using Robust.Shared.Interfaces.Network; using Robust.Shared.Interfaces.Network;
using Robust.Shared.Interfaces.Timing; using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Players; using Robust.Shared.Players;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.Timing;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
using Logger = Robust.Shared.Log.Logger;
using MidiEvent = Robust.Shared.Audio.Midi.MidiEvent; using MidiEvent = Robust.Shared.Audio.Midi.MidiEvent;
using Timer = Robust.Shared.Timers.Timer; using Timer = Robust.Shared.Timers.Timer;
@@ -32,24 +25,23 @@ namespace Content.Client.GameObjects.Components.Instruments
/// <summary> /// <summary>
/// Called when a midi song stops playing. /// Called when a midi song stops playing.
/// </summary> /// </summary>
public event Action OnMidiPlaybackEnded; public event Action? OnMidiPlaybackEnded;
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly IMidiManager _midiManager; [Dependency] private readonly IMidiManager _midiManager = default!;
[Dependency] private readonly IGameTiming _gameTiming; [Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IClientNetManager _netManager; [Dependency] private readonly IClientNetManager _netManager = default!;
#pragma warning restore 649 #pragma warning restore 649
[CanBeNull] private IMidiRenderer? _renderer;
private IMidiRenderer _renderer;
private byte _instrumentProgram = 1; private byte _instrumentProgram = 1;
private byte _instrumentBank = 0; private byte _instrumentBank;
private uint _sequenceDelay = 0; private uint _sequenceDelay;
private uint _sequenceStartTick; private uint _sequenceStartTick;
@@ -209,7 +201,7 @@ namespace Content.Client.GameObjects.Components.Instruments
serializer.DataField(ref _instrumentBank, "bank", (byte) 0); serializer.DataField(ref _instrumentBank, "bank", (byte) 0);
} }
public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession session = null) public override void HandleNetworkMessage(ComponentMessage message, INetChannel channel, ICommonSession? session = null)
{ {
base.HandleNetworkMessage(message, channel, session); base.HandleNetworkMessage(message, channel, session);
@@ -240,7 +232,7 @@ namespace Content.Client.GameObjects.Components.Instruments
.Min(x => x.Tick) - 1; .Min(x => x.Tick) - 1;
} }
var sqrtLag = MathF.Sqrt(_netManager.ServerChannel.Ping / 1000f); var sqrtLag = MathF.Sqrt(_netManager.ServerChannel!.Ping / 1000f);
var delay = (uint) (_renderer!.SequencerTimeScale * (.2 + sqrtLag)); var delay = (uint) (_renderer!.SequencerTimeScale * (.2 + sqrtLag));
var delta = delay - _sequenceStartTick; var delta = delay - _sequenceStartTick;
@@ -265,12 +257,12 @@ namespace Content.Client.GameObjects.Components.Instruments
} }
break; break;
case InstrumentStartMidiMessage startMidiMessage: case InstrumentStartMidiMessage _:
{ {
SetupRenderer(true); SetupRenderer(true);
break; break;
} }
case InstrumentStopMidiMessage stopMidiMessage: case InstrumentStopMidiMessage _:
{ {
EndRenderer(true); EndRenderer(true);
break; break;
@@ -278,7 +270,7 @@ namespace Content.Client.GameObjects.Components.Instruments
} }
} }
public override void HandleComponentState(ComponentState curState, ComponentState nextState) public override void HandleComponentState(ComponentState? curState, ComponentState? nextState)
{ {
base.HandleComponentState(curState, nextState); base.HandleComponentState(curState, nextState);
if (!(curState is InstrumentState state)) return; if (!(curState is InstrumentState state)) return;
@@ -370,7 +362,7 @@ namespace Content.Client.GameObjects.Components.Instruments
private TimeSpan _lastMeasured = TimeSpan.MinValue; private TimeSpan _lastMeasured = TimeSpan.MinValue;
private int _sentWithinASec = 0; private int _sentWithinASec;
private static readonly TimeSpan OneSecAgo = TimeSpan.FromSeconds(-1); private static readonly TimeSpan OneSecAgo = TimeSpan.FromSeconds(-1);

View File

@@ -28,7 +28,7 @@ namespace Content.Client.GameObjects.Components.Mobs
/// <summary> /// <summary>
/// An enum representing the current state being applied to the user /// An enum representing the current state being applied to the user
/// </summary> /// </summary>
private readonly List<OverlayContainer> _currentEffects = new List<OverlayContainer>(); private List<OverlayContainer> _currentEffects = new List<OverlayContainer>();
[ViewVariables(VVAccess.ReadOnly)] [ViewVariables(VVAccess.ReadOnly)]
public List<OverlayContainer> ActiveOverlays public List<OverlayContainer> ActiveOverlays
@@ -49,7 +49,9 @@ namespace Content.Client.GameObjects.Components.Mobs
switch (message) switch (message)
{ {
case PlayerAttachedMsg _: case PlayerAttachedMsg _:
SetEffects(ActiveOverlays); var overlays = new List<OverlayContainer>(_currentEffects);
_currentEffects.Clear();
SetEffects(overlays);
break; break;
case PlayerDetachedMsg _: case PlayerDetachedMsg _:
ActiveOverlays = new List<OverlayContainer>(); ActiveOverlays = new List<OverlayContainer>();
@@ -61,14 +63,20 @@ namespace Content.Client.GameObjects.Components.Mobs
{ {
base.HandleComponentState(curState, nextState); base.HandleComponentState(curState, nextState);
if(_playerManager?.LocalPlayer != null && _playerManager.LocalPlayer.ControlledEntity != Owner) if (!(curState is OverlayEffectComponentState state))
return;
if (!(curState is OverlayEffectComponentState state) || ActiveOverlays.Equals(state.Overlays))
{ {
return; return;
} }
if (_playerManager?.LocalPlayer != null && _playerManager.LocalPlayer.ControlledEntity != Owner)
{
_currentEffects = state.Overlays;
return;
}
if (ActiveOverlays.Equals(state.Overlays))
return;
ActiveOverlays = state.Overlays; ActiveOverlays = state.Overlays;
} }

View File

@@ -1,5 +1,5 @@
using Content.Shared.GameObjects.Components.Mobs; #nullable enable
using JetBrains.Annotations; using Content.Shared.GameObjects.Components.Mobs;
using Robust.Client.Graphics; using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
@@ -9,7 +9,7 @@ namespace Content.Client.GameObjects.Components.Mobs
{ {
public readonly StatusEffect Effect; public readonly StatusEffect Effect;
public StatusControl(StatusEffect effect, [CanBeNull] Texture texture) public StatusControl(StatusEffect effect, Texture? texture)
{ {
Effect = effect; Effect = effect;

View File

@@ -1,9 +1,8 @@
#nullable enable
using Content.Shared.GameObjects.Components.Mobs; using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.GameObjects.Components.Movement; using Content.Shared.GameObjects.Components.Movement;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
#nullable enable
namespace Content.Client.GameObjects.Components.Mobs namespace Content.Client.GameObjects.Components.Mobs
{ {
[RegisterComponent] [RegisterComponent]

View File

@@ -1,14 +1,13 @@
#nullable enable
using Content.Shared.GameObjects.Components.Movement; using Content.Shared.GameObjects.Components.Movement;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Map; using Robust.Shared.Map;
#nullable enable
namespace Content.Client.GameObjects.Components.Movement namespace Content.Client.GameObjects.Components.Movement
{ {
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(IMoverComponent))] [ComponentReference(typeof(IMoverComponent))]
public class PlayerInputMoverComponent : SharedPlayerInputMoverComponent, IMoverComponent public class PlayerInputMoverComponent : SharedPlayerInputMoverComponent
{ {
public override GridCoordinates LastPosition { get; set; } public override GridCoordinates LastPosition { get; set; }
public override float StepSoundDistance { get; set; } public override float StepSoundDistance { get; set; }

View File

@@ -1,9 +1,8 @@
#nullable enable
using Content.Shared.GameObjects.Components.Movement; using Content.Shared.GameObjects.Components.Movement;
using Content.Shared.GameObjects.Components.Nutrition; using Content.Shared.GameObjects.Components.Nutrition;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
#nullable enable
namespace Content.Client.GameObjects.Components.Nutrition namespace Content.Client.GameObjects.Components.Nutrition
{ {
[RegisterComponent] [RegisterComponent]

View File

@@ -1,9 +1,8 @@
#nullable enable
using Content.Shared.GameObjects.Components.Movement; using Content.Shared.GameObjects.Components.Movement;
using Content.Shared.GameObjects.Components.Nutrition; using Content.Shared.GameObjects.Components.Nutrition;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
#nullable enable
namespace Content.Client.GameObjects.Components.Nutrition namespace Content.Client.GameObjects.Components.Nutrition
{ {
[RegisterComponent] [RegisterComponent]

View File

@@ -1,8 +1,7 @@
#nullable enable
using Content.Shared.GameObjects.Components.Projectiles; using Content.Shared.GameObjects.Components.Projectiles;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
#nullable enable
namespace Content.Client.GameObjects.Components.Projectiles namespace Content.Client.GameObjects.Components.Projectiles
{ {
[RegisterComponent] [RegisterComponent]

View File

@@ -16,7 +16,7 @@ using Timer = Robust.Shared.Timers.Timer;
namespace Content.Client.GameObjects.Components.Weapons namespace Content.Client.GameObjects.Components.Weapons
{ {
[RegisterComponent] [RegisterComponent]
public sealed class ClientFlashableComponent : SharedFlashableComponent public sealed class FlashableComponent : SharedFlashableComponent
{ {
private CancellationTokenSource _cancelToken; private CancellationTokenSource _cancelToken;
private TimeSpan _startTime; private TimeSpan _startTime;
@@ -31,7 +31,7 @@ namespace Content.Client.GameObjects.Components.Weapons
} }
var playerManager = IoCManager.Resolve<IPlayerManager>(); var playerManager = IoCManager.Resolve<IPlayerManager>();
if (playerManager.LocalPlayer.ControlledEntity != Owner) if (playerManager?.LocalPlayer != null && playerManager.LocalPlayer.ControlledEntity != Owner)
{ {
return; return;
} }

View File

@@ -1,4 +1,5 @@
using Content.Shared.GameObjects.Components.Movement; #nullable enable
using Content.Shared.GameObjects.Components.Movement;
using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Physics; using Content.Shared.Physics;
using JetBrains.Annotations; using JetBrains.Annotations;
@@ -7,8 +8,6 @@ using Robust.Client.Player;
using Robust.Shared.GameObjects.Components; using Robust.Shared.GameObjects.Components;
using Robust.Shared.IoC; using Robust.Shared.IoC;
#nullable enable
namespace Content.Client.GameObjects.EntitySystems namespace Content.Client.GameObjects.EntitySystems
{ {
[UsedImplicitly] [UsedImplicitly]

View File

@@ -14,6 +14,7 @@ namespace Content.Client.Input
var common = contexts.GetContext("common"); var common = contexts.GetContext("common");
common.AddFunction(ContentKeyFunctions.FocusChat); common.AddFunction(ContentKeyFunctions.FocusChat);
common.AddFunction(ContentKeyFunctions.FocusOOC); common.AddFunction(ContentKeyFunctions.FocusOOC);
common.AddFunction(ContentKeyFunctions.FocusAdminChat);
common.AddFunction(ContentKeyFunctions.ExamineEntity); common.AddFunction(ContentKeyFunctions.ExamineEntity);
common.AddFunction(ContentKeyFunctions.OpenTutorial); common.AddFunction(ContentKeyFunctions.OpenTutorial);
common.AddFunction(ContentKeyFunctions.TakeScreenshot); common.AddFunction(ContentKeyFunctions.TakeScreenshot);

View File

@@ -4,6 +4,7 @@ using Content.Client.Chat;
using Content.Client.Interfaces.Chat; using Content.Client.Interfaces.Chat;
using Content.Client.UserInterface; using Content.Client.UserInterface;
using Content.Shared.Input; using Content.Shared.Input;
using Robust.Client.Console;
using Robust.Client.Interfaces.Input; using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.State; using Robust.Client.Interfaces.State;
using Robust.Client.Interfaces.UserInterface; using Robust.Client.Interfaces.UserInterface;
@@ -25,6 +26,7 @@ namespace Content.Client.State
[Dependency] private readonly IGameHud _gameHud; [Dependency] private readonly IGameHud _gameHud;
[Dependency] private readonly IInputManager _inputManager; [Dependency] private readonly IInputManager _inputManager;
[Dependency] private readonly IChatManager _chatManager; [Dependency] private readonly IChatManager _chatManager;
[Dependency] private readonly IClientConGroupController _groupController = default!;
#pragma warning restore 649 #pragma warning restore 649
[ViewVariables] private ChatBox _gameChat; [ViewVariables] private ChatBox _gameChat;
@@ -34,6 +36,7 @@ namespace Content.Client.State
base.Startup(); base.Startup();
_gameChat = new ChatBox(); _gameChat = new ChatBox();
_userInterfaceManager.StateRoot.AddChild(_gameChat); _userInterfaceManager.StateRoot.AddChild(_gameChat);
LayoutContainer.SetAnchorAndMarginPreset(_gameChat, LayoutContainer.LayoutPreset.TopRight, margin: 10); LayoutContainer.SetAnchorAndMarginPreset(_gameChat, LayoutContainer.LayoutPreset.TopRight, margin: 10);
LayoutContainer.SetAnchorAndMarginPreset(_gameChat, LayoutContainer.LayoutPreset.TopRight, margin: 10); LayoutContainer.SetAnchorAndMarginPreset(_gameChat, LayoutContainer.LayoutPreset.TopRight, margin: 10);
@@ -50,6 +53,9 @@ namespace Content.Client.State
_inputManager.SetInputCommand(ContentKeyFunctions.FocusOOC, _inputManager.SetInputCommand(ContentKeyFunctions.FocusOOC,
InputCmdHandler.FromDelegate(s => FocusOOC(_gameChat))); InputCmdHandler.FromDelegate(s => FocusOOC(_gameChat)));
_inputManager.SetInputCommand(ContentKeyFunctions.FocusAdminChat,
InputCmdHandler.FromDelegate(s => FocusAdminChat(_gameChat)));
} }
public override void Shutdown() public override void Shutdown()
@@ -81,5 +87,17 @@ namespace Content.Client.State
chat.Input.GrabKeyboardFocus(); chat.Input.GrabKeyboardFocus();
chat.Input.InsertAtCursor("["); chat.Input.InsertAtCursor("[");
} }
internal static void FocusAdminChat(ChatBox chat)
{
if (chat == null || chat.UserInterfaceManager.KeyboardFocused != null)
{
return;
}
chat.Input.IgnoreNext = true;
chat.Input.GrabKeyboardFocus();
chat.Input.InsertAtCursor("]");
}
} }
} }

View File

@@ -1,3 +1,4 @@
#nullable enable
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@@ -13,8 +14,6 @@ using Robust.Shared.Localization;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.Utility; using Robust.Shared.Utility;
#nullable enable
namespace Content.Client.UserInterface namespace Content.Client.UserInterface
{ {
public sealed class CreditsWindow : SS14Window public sealed class CreditsWindow : SS14Window

View File

@@ -76,6 +76,7 @@ Open character window: [color=#a4885c]{8}[/color]
Open crafting window: [color=#a4885c]{9}[/color] Open crafting window: [color=#a4885c]{9}[/color]
Focus chat: [color=#a4885c]{10}[/color] Focus chat: [color=#a4885c]{10}[/color]
Focus OOC: [color=#a4885c]{26}[/color] Focus OOC: [color=#a4885c]{26}[/color]
Focus Admin Chat: [color=#a4885c]{27}[/color]
Use hand/object in hand: [color=#a4885c]{22}[/color] Use hand/object in hand: [color=#a4885c]{22}[/color]
Do wide attack: [color=#a4885c]{23}[/color] Do wide attack: [color=#a4885c]{23}[/color]
Use targeted entity: [color=#a4885c]{11}[/color] Use targeted entity: [color=#a4885c]{11}[/color]
@@ -112,7 +113,8 @@ Toggle sandbox window: [color=#a4885c]{21}[/color]",
Key(WideAttack), Key(WideAttack),
Key(SmartEquipBackpack), Key(SmartEquipBackpack),
Key(SmartEquipBelt), Key(SmartEquipBelt),
Key(FocusOOC))); Key(FocusOOC),
Key(FocusAdminChat)));
//Gameplay //Gameplay
VBox.AddChild(new Label { FontOverride = headerFont, Text = "\nGameplay" }); VBox.AddChild(new Label { FontOverride = headerFont, Text = "\nGameplay" });

View File

@@ -1,3 +1,4 @@
#nullable enable
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
@@ -15,8 +16,6 @@ using Robust.Shared.IoC;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Timing; using Robust.Shared.Timing;
#nullable enable
namespace Content.IntegrationTests.Tests.Networking namespace Content.IntegrationTests.Tests.Networking
{ {
// This test checks that the prediction & reconciling system is working correctly with a simple boolean flag. // This test checks that the prediction & reconciling system is working correctly with a simple boolean flag.

View File

@@ -1,14 +1,15 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.AI.Operators; using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Inventory; using Content.Server.AI.Operators.Inventory;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Clothing; using Content.Server.AI.Utility.Considerations.Clothing;
using Content.Server.AI.Utility.Considerations.Inventory; using Content.Server.AI.Utility.Considerations.Inventory;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Inventory;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Clothing.Gloves namespace Content.Server.AI.Utility.Actions.Clothing.Gloves
{ {
@@ -36,12 +37,18 @@ namespace Content.Server.AI.Utility.Actions.Clothing.Gloves
base.UpdateBlackboard(context); base.UpdateBlackboard(context);
context.GetState<TargetEntityState>().SetValue(_entity); context.GetState<TargetEntityState>().SetValue(_entity);
} }
protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
{
var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
protected override Consideration[] Considerations { get; } = { return new[]
new ClothingInSlotCon(EquipmentSlotDefines.Slots.GLOVES, {
new InverseBoolCurve()), considerationsManager.Get<ClothingInSlotCon>().Slot(EquipmentSlotDefines.Slots.GLOVES, context)
new CanPutTargetInHandsCon( .InverseBoolCurve(context),
new BoolCurve()), considerationsManager.Get<CanPutTargetInHandsCon>()
}; .BoolCurve(context),
};
}
} }
} }

View File

@@ -1,12 +1,14 @@
using System;
using System.Collections.Generic;
using Content.Server.AI.Operators.Sequences; using Content.Server.AI.Operators.Sequences;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Clothing; using Content.Server.AI.Utility.Considerations.Clothing;
using Content.Server.AI.Utility.Considerations.Inventory; using Content.Server.AI.Utility.Considerations.Inventory;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Inventory;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Clothing.Gloves namespace Content.Server.AI.Utility.Actions.Clothing.Gloves
{ {
@@ -30,14 +32,20 @@ namespace Content.Server.AI.Utility.Actions.Clothing.Gloves
base.UpdateBlackboard(context); base.UpdateBlackboard(context);
context.GetState<TargetEntityState>().SetValue(_entity); context.GetState<TargetEntityState>().SetValue(_entity);
} }
protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
{
var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
protected override Consideration[] Considerations { get; } = { return new[]
new ClothingInSlotCon(EquipmentSlotDefines.Slots.GLOVES, {
new InverseBoolCurve()), considerationsManager.Get<ClothingInSlotCon>().Slot(EquipmentSlotDefines.Slots.GLOVES, context)
new CanPutTargetInHandsCon( .InverseBoolCurve(context),
new BoolCurve()), considerationsManager.Get<CanPutTargetInHandsCon>()
new ClothingInInventoryCon(EquipmentSlotDefines.SlotFlags.GLOVES, .BoolCurve(context),
new InverseBoolCurve()), considerationsManager.Get<ClothingInInventoryCon>().Slot(EquipmentSlotDefines.SlotFlags.GLOVES, context)
}; .InverseBoolCurve(context)
};
}
} }
} }

View File

@@ -1,14 +1,15 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.AI.Operators; using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Inventory; using Content.Server.AI.Operators.Inventory;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Clothing; using Content.Server.AI.Utility.Considerations.Clothing;
using Content.Server.AI.Utility.Considerations.Inventory; using Content.Server.AI.Utility.Considerations.Inventory;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Inventory;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Clothing.Head namespace Content.Server.AI.Utility.Actions.Clothing.Head
{ {
@@ -37,11 +38,18 @@ namespace Content.Server.AI.Utility.Actions.Clothing.Head
context.GetState<TargetEntityState>().SetValue(_entity); context.GetState<TargetEntityState>().SetValue(_entity);
} }
protected override Consideration[] Considerations { get; } = { protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
new ClothingInSlotCon(EquipmentSlotDefines.Slots.HEAD, {
new InverseBoolCurve()), var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
new CanPutTargetInHandsCon(
new BoolCurve()), return new[]
}; {
considerationsManager.Get<ClothingInSlotCon>().Slot(EquipmentSlotDefines.Slots.HEAD, context)
.InverseBoolCurve(context),
considerationsManager.Get<CanPutTargetInHandsCon>()
.BoolCurve(context),
};
}
} }
} }

View File

@@ -1,12 +1,14 @@
using System;
using System.Collections.Generic;
using Content.Server.AI.Operators.Sequences; using Content.Server.AI.Operators.Sequences;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Clothing; using Content.Server.AI.Utility.Considerations.Clothing;
using Content.Server.AI.Utility.Considerations.Inventory; using Content.Server.AI.Utility.Considerations.Inventory;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Inventory;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Clothing.Head namespace Content.Server.AI.Utility.Actions.Clothing.Head
{ {
@@ -31,13 +33,19 @@ namespace Content.Server.AI.Utility.Actions.Clothing.Head
context.GetState<TargetEntityState>().SetValue(_entity); context.GetState<TargetEntityState>().SetValue(_entity);
} }
protected override Consideration[] Considerations { get; } = { protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
new ClothingInSlotCon(EquipmentSlotDefines.Slots.HEAD, {
new InverseBoolCurve()), var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
new CanPutTargetInHandsCon(
new BoolCurve()), return new[]
new ClothingInInventoryCon(EquipmentSlotDefines.SlotFlags.HEAD, {
new InverseBoolCurve()), considerationsManager.Get<ClothingInSlotCon>().Slot(EquipmentSlotDefines.Slots.HEAD, context)
}; .InverseBoolCurve(context),
considerationsManager.Get<CanPutTargetInHandsCon>()
.BoolCurve(context),
considerationsManager.Get<ClothingInInventoryCon>().Slot(EquipmentSlotDefines.SlotFlags.HEAD, context)
.InverseBoolCurve(context)
};
}
} }
} }

View File

@@ -1,14 +1,15 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.AI.Operators; using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Inventory; using Content.Server.AI.Operators.Inventory;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Clothing; using Content.Server.AI.Utility.Considerations.Clothing;
using Content.Server.AI.Utility.Considerations.Inventory; using Content.Server.AI.Utility.Considerations.Inventory;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Inventory;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Clothing.OuterClothing namespace Content.Server.AI.Utility.Actions.Clothing.OuterClothing
{ {
@@ -37,11 +38,17 @@ namespace Content.Server.AI.Utility.Actions.Clothing.OuterClothing
context.GetState<TargetEntityState>().SetValue(_entity); context.GetState<TargetEntityState>().SetValue(_entity);
} }
protected override Consideration[] Considerations { get; } = { protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
new ClothingInSlotCon(EquipmentSlotDefines.Slots.OUTERCLOTHING, {
new InverseBoolCurve()), var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
new CanPutTargetInHandsCon(
new BoolCurve()), return new[]
}; {
considerationsManager.Get<ClothingInSlotCon>().Slot(EquipmentSlotDefines.Slots.OUTERCLOTHING, context)
.InverseBoolCurve(context),
considerationsManager.Get<CanPutTargetInHandsCon>()
.BoolCurve(context),
};
}
} }
} }

View File

@@ -1,12 +1,14 @@
using System;
using System.Collections.Generic;
using Content.Server.AI.Operators.Sequences; using Content.Server.AI.Operators.Sequences;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Clothing; using Content.Server.AI.Utility.Considerations.Clothing;
using Content.Server.AI.Utility.Considerations.Inventory; using Content.Server.AI.Utility.Considerations.Inventory;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Inventory;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Clothing.OuterClothing namespace Content.Server.AI.Utility.Actions.Clothing.OuterClothing
{ {
@@ -31,13 +33,19 @@ namespace Content.Server.AI.Utility.Actions.Clothing.OuterClothing
context.GetState<TargetEntityState>().SetValue(_entity); context.GetState<TargetEntityState>().SetValue(_entity);
} }
protected override Consideration[] Considerations { get; } = { protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
new ClothingInSlotCon(EquipmentSlotDefines.Slots.OUTERCLOTHING, {
new InverseBoolCurve()), var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
new CanPutTargetInHandsCon(
new BoolCurve()), return new[]
new ClothingInInventoryCon(EquipmentSlotDefines.SlotFlags.OUTERCLOTHING, {
new InverseBoolCurve()), considerationsManager.Get<ClothingInSlotCon>().Slot(EquipmentSlotDefines.Slots.OUTERCLOTHING, context)
}; .InverseBoolCurve(context),
considerationsManager.Get<CanPutTargetInHandsCon>()
.BoolCurve(context),
considerationsManager.Get<ClothingInInventoryCon>().Slot(EquipmentSlotDefines.SlotFlags.OUTERCLOTHING, context)
.InverseBoolCurve(context)
};
}
} }
} }

View File

@@ -1,14 +1,15 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.AI.Operators; using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Inventory; using Content.Server.AI.Operators.Inventory;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Clothing; using Content.Server.AI.Utility.Considerations.Clothing;
using Content.Server.AI.Utility.Considerations.Inventory; using Content.Server.AI.Utility.Considerations.Inventory;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Inventory;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Clothing.Shoes namespace Content.Server.AI.Utility.Actions.Clothing.Shoes
{ {
@@ -37,11 +38,17 @@ namespace Content.Server.AI.Utility.Actions.Clothing.Shoes
context.GetState<TargetEntityState>().SetValue(_entity); context.GetState<TargetEntityState>().SetValue(_entity);
} }
protected override Consideration[] Considerations { get; } = { protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
new ClothingInSlotCon(EquipmentSlotDefines.Slots.SHOES, {
new InverseBoolCurve()), var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
new CanPutTargetInHandsCon(
new BoolCurve()), return new[]
}; {
considerationsManager.Get<ClothingInSlotCon>().Slot(EquipmentSlotDefines.Slots.SHOES, context)
.InverseBoolCurve(context),
considerationsManager.Get<CanPutTargetInHandsCon>()
.BoolCurve(context),
};
}
} }
} }

View File

@@ -1,12 +1,14 @@
using System;
using System.Collections.Generic;
using Content.Server.AI.Operators.Sequences; using Content.Server.AI.Operators.Sequences;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Clothing; using Content.Server.AI.Utility.Considerations.Clothing;
using Content.Server.AI.Utility.Considerations.Inventory; using Content.Server.AI.Utility.Considerations.Inventory;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Inventory;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Clothing.Shoes namespace Content.Server.AI.Utility.Actions.Clothing.Shoes
{ {
@@ -31,13 +33,19 @@ namespace Content.Server.AI.Utility.Actions.Clothing.Shoes
context.GetState<TargetEntityState>().SetValue(_entity); context.GetState<TargetEntityState>().SetValue(_entity);
} }
protected override Consideration[] Considerations { get; } = { protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
new ClothingInSlotCon(EquipmentSlotDefines.Slots.SHOES, {
new InverseBoolCurve()), var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
new CanPutTargetInHandsCon(
new BoolCurve()), return new[]
new ClothingInInventoryCon(EquipmentSlotDefines.SlotFlags.SHOES, {
new InverseBoolCurve()), considerationsManager.Get<ClothingInSlotCon>().Slot(EquipmentSlotDefines.Slots.SHOES, context)
}; .InverseBoolCurve(context),
considerationsManager.Get<CanPutTargetInHandsCon>()
.BoolCurve(context),
considerationsManager.Get<ClothingInInventoryCon>().Slot(EquipmentSlotDefines.SlotFlags.SHOES, context)
.InverseBoolCurve(context)
};
}
} }
} }

View File

@@ -1,14 +1,15 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.AI.Operators; using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Inventory; using Content.Server.AI.Operators.Inventory;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Combat.Melee; using Content.Server.AI.Utility.Considerations.Combat.Melee;
using Content.Server.AI.Utility.Considerations.Inventory; using Content.Server.AI.Utility.Considerations.Inventory;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Combat; using Content.Server.AI.WorldState.States.Combat;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Combat.Melee namespace Content.Server.AI.Utility.Actions.Combat.Melee
{ {
@@ -37,15 +38,21 @@ namespace Content.Server.AI.Utility.Actions.Combat.Melee
context.GetState<TargetEntityState>().SetValue(_entity); context.GetState<TargetEntityState>().SetValue(_entity);
} }
protected override Consideration[] Considerations { get; } = { protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
new MeleeWeaponEquippedCon( {
new InverseBoolCurve()), var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
new CanPutTargetInHandsCon(
new BoolCurve()), return new[]
new MeleeWeaponSpeedCon( {
new QuadraticCurve(1.0f, 0.5f, 0.0f, 0.0f)), considerationsManager.Get<MeleeWeaponEquippedCon>()
new MeleeWeaponDamageCon( .InverseBoolCurve(context),
new QuadraticCurve(1.0f, 0.25f, 0.0f, 0.0f)), considerationsManager.Get<CanPutTargetInHandsCon>()
}; .BoolCurve(context),
considerationsManager.Get<MeleeWeaponSpeedCon>()
.QuadraticCurve(context, 1.0f, 0.5f, 0.0f, 0.0f),
considerationsManager.Get<MeleeWeaponDamageCon>()
.QuadraticCurve(context, 1.0f, 0.25f, 0.0f, 0.0f),
};
}
} }
} }

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.AI.Operators; using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Combat; using Content.Server.AI.Operators.Combat;
@@ -7,7 +8,6 @@ using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Combat; using Content.Server.AI.Utility.Considerations.Combat;
using Content.Server.AI.Utility.Considerations.Combat.Melee; using Content.Server.AI.Utility.Considerations.Combat.Melee;
using Content.Server.AI.Utility.Considerations.Movement; using Content.Server.AI.Utility.Considerations.Movement;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Combat; using Content.Server.AI.WorldState.States.Combat;
@@ -15,6 +15,7 @@ using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.AI.WorldState.States.Movement; using Content.Server.AI.WorldState.States.Movement;
using Content.Server.GameObjects.Components.Weapon.Melee; using Content.Server.GameObjects.Components.Weapon.Melee;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Combat.Melee namespace Content.Server.AI.Utility.Actions.Combat.Melee
{ {
@@ -30,16 +31,15 @@ namespace Content.Server.AI.Utility.Actions.Combat.Melee
public override void SetupOperators(Blackboard context) public override void SetupOperators(Blackboard context)
{ {
var equipped = context.GetState<EquippedEntityState>().GetValue();
MoveToEntityOperator moveOperator; MoveToEntityOperator moveOperator;
var equipped = context.GetState<EquippedEntityState>().GetValue();
if (equipped != null && equipped.TryGetComponent(out MeleeWeaponComponent meleeWeaponComponent)) if (equipped != null && equipped.TryGetComponent(out MeleeWeaponComponent meleeWeaponComponent))
{ {
moveOperator = new MoveToEntityOperator(Owner, _entity, meleeWeaponComponent.Range - 0.01f); moveOperator = new MoveToEntityOperator(Owner, _entity, meleeWeaponComponent.Range - 0.01f);
} }
// I think it's possible for this to happen given planning is time-sliced?
// TODO: At this point we should abort
else else
{ {
// TODO: Abort
moveOperator = new MoveToEntityOperator(Owner, _entity); moveOperator = new MoveToEntityOperator(Owner, _entity);
} }
@@ -58,27 +58,28 @@ namespace Content.Server.AI.Utility.Actions.Combat.Melee
var equipped = context.GetState<EquippedEntityState>().GetValue(); var equipped = context.GetState<EquippedEntityState>().GetValue();
context.GetState<WeaponEntityState>().SetValue(equipped); context.GetState<WeaponEntityState>().SetValue(equipped);
} }
protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
{
var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
protected override Consideration[] Considerations { get; } = { return new[]
// Check if we have a weapon; easy-out {
new MeleeWeaponEquippedCon( considerationsManager.Get<MeleeWeaponEquippedCon>()
new BoolCurve()), .BoolCurve(context),
// Don't attack a dead target considerationsManager.Get<TargetIsDeadCon>()
new TargetIsDeadCon( .InverseBoolCurve(context),
new InverseBoolCurve()), considerationsManager.Get<TargetIsCritCon>()
// Deprioritise a target in crit .QuadraticCurve(context, -0.8f, 1.0f, 1.0f, 0.0f),
new TargetIsCritCon( considerationsManager.Get<DistanceCon>()
new QuadraticCurve(-0.8f, 1.0f, 1.0f, 0.0f)), .QuadraticCurve(context, 1.0f, 1.0f, 0.02f, 0.0f),
// Somewhat prioritise distance considerationsManager.Get<TargetHealthCon>()
new DistanceCon( .QuadraticCurve(context, 1.0f, 0.4f, 0.0f, -0.02f),
new QuadraticCurve(-1.0f, 1.0f, 1.02f, 0.0f)), considerationsManager.Get<MeleeWeaponSpeedCon>()
// Prefer weaker targets .QuadraticCurve(context, 1.0f, 0.5f, 0.0f, 0.0f),
new TargetHealthCon( considerationsManager.Get<MeleeWeaponDamageCon>()
new QuadraticCurve(1.0f, 0.4f, 0.0f, -0.02f)), .QuadraticCurve(context, 1.0f, 0.25f, 0.0f, 0.0f),
new MeleeWeaponSpeedCon( };
new QuadraticCurve(1.0f, 0.5f, 0.0f, 0.0f)), }
new MeleeWeaponDamageCon(
new QuadraticCurve(1.0f, 0.25f, 0.0f, 0.0f)),
};
} }
} }

View File

@@ -1,14 +1,16 @@
using System;
using System.Collections.Generic;
using Content.Server.AI.Operators.Sequences; using Content.Server.AI.Operators.Sequences;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Combat.Melee; using Content.Server.AI.Utility.Considerations.Combat.Melee;
using Content.Server.AI.Utility.Considerations.Containers; using Content.Server.AI.Utility.Considerations.Containers;
using Content.Server.AI.Utility.Considerations.Hands; using Content.Server.AI.Utility.Considerations.Hands;
using Content.Server.AI.Utility.Considerations.Movement; using Content.Server.AI.Utility.Considerations.Movement;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Combat; using Content.Server.AI.WorldState.States.Combat;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Combat.Melee namespace Content.Server.AI.Utility.Actions.Combat.Melee
{ {
@@ -33,20 +35,26 @@ namespace Content.Server.AI.Utility.Actions.Combat.Melee
context.GetState<TargetEntityState>().SetValue(_entity); context.GetState<TargetEntityState>().SetValue(_entity);
context.GetState<WeaponEntityState>().SetValue(_entity); context.GetState<WeaponEntityState>().SetValue(_entity);
} }
protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
{
var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
protected override Consideration[] Considerations { get; } = { return new[]
new TargetAccessibleCon( {
new BoolCurve()), considerationsManager.Get<TargetAccessibleCon>()
new FreeHandCon( .BoolCurve(context),
new BoolCurve()), considerationsManager.Get<FreeHandCon>()
new HasMeleeWeaponCon( .BoolCurve(context),
new InverseBoolCurve()), considerationsManager.Get<HasMeleeWeaponCon>()
new DistanceCon( .InverseBoolCurve(context),
new QuadraticCurve(-1.0f, 1.0f, 1.02f, 0.0f)), considerationsManager.Get<DistanceCon>()
new MeleeWeaponDamageCon( .QuadraticCurve(context, 1.0f, 1.0f, 0.02f, 0.0f),
new QuadraticCurve(1.0f, 0.25f, 0.0f, 0.0f)), considerationsManager.Get<MeleeWeaponDamageCon>()
new MeleeWeaponSpeedCon( .QuadraticCurve(context, 1.0f, 0.25f, 0.0f, 0.0f),
new QuadraticCurve(-1.0f, 0.5f, 1.0f, 0.0f)), considerationsManager.Get<MeleeWeaponSpeedCon>()
}; .QuadraticCurve(context, -1.0f, 0.5f, 1.0f, 0.0f),
};
}
} }
} }

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.AI.Operators; using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Combat.Melee; using Content.Server.AI.Operators.Combat.Melee;
@@ -6,13 +7,13 @@ using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Combat; using Content.Server.AI.Utility.Considerations.Combat;
using Content.Server.AI.Utility.Considerations.Combat.Melee; using Content.Server.AI.Utility.Considerations.Combat.Melee;
using Content.Server.AI.Utility.Considerations.Movement; using Content.Server.AI.Utility.Considerations.Movement;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Combat; using Content.Server.AI.WorldState.States.Combat;
using Content.Server.AI.WorldState.States.Movement; using Content.Server.AI.WorldState.States.Movement;
using Content.Server.GameObjects.Components.Weapon.Melee; using Content.Server.GameObjects.Components.Weapon.Melee;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Combat.Melee namespace Content.Server.AI.Utility.Actions.Combat.Melee
{ {
@@ -56,23 +57,25 @@ namespace Content.Server.AI.Utility.Actions.Combat.Melee
context.GetState<WeaponEntityState>().SetValue(Owner); context.GetState<WeaponEntityState>().SetValue(Owner);
} }
protected override Consideration[] Considerations { get; } = { protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
new CanUnarmedCombatCon( {
new BoolCurve()), var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
// Don't attack a dead target
new TargetIsDeadCon( return new[]
new InverseBoolCurve()), {
// Deprioritise a target in crit considerationsManager.Get<CanUnarmedCombatCon>()
new TargetIsCritCon( .BoolCurve(context),
new QuadraticCurve(-0.8f, 1.0f, 1.0f, 0.0f)), considerationsManager.Get<TargetIsDeadCon>()
// Somewhat prioritise distance .InverseBoolCurve(context),
new DistanceCon( considerationsManager.Get<TargetIsCritCon>()
new QuadraticCurve(-1.0f, 1.0f, 1.02f, 0.0f)), .QuadraticCurve(context, -0.8f, 1.0f, 1.0f, 0.0f),
// Prefer weaker targets considerationsManager.Get<DistanceCon>()
new TargetHealthCon( .QuadraticCurve(context, -1.0f, 1.0f, 1.02f, 0.0f),
new QuadraticCurve(1.0f, 0.4f, 0.0f, -0.02f)), considerationsManager.Get<TargetHealthCon>()
// TODO: Consider our Speed and Damage to compare this to using a weapon .QuadraticCurve(context, 1.0f, 0.4f, 0.0f, -0.02f),
// Also need to unequip our weapon if we have one (xenos can't hold one so no issue for now) // TODO: Consider our Speed and Damage to compare this to using a weapon
}; // Also need to unequip our weapon if we have one (xenos can't hold one so no issue for now)
};
}
} }
} }

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.AI.Operators; using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Inventory; using Content.Server.AI.Operators.Inventory;
@@ -5,10 +6,10 @@ using Content.Server.AI.Operators.Movement;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Movement; using Content.Server.AI.Utility.Considerations.Movement;
using Content.Server.AI.Utility.Considerations.State; using Content.Server.AI.Utility.Considerations.State;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States.Inventory; using Content.Server.AI.WorldState.States.Inventory;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Idle namespace Content.Server.AI.Utility.Actions.Idle
{ {
@@ -21,13 +22,6 @@ namespace Content.Server.AI.Utility.Actions.Idle
public CloseLastEntityStorage(IEntity owner) : base(owner) {} public CloseLastEntityStorage(IEntity owner) : base(owner) {}
protected override Consideration[] Considerations => new Consideration[]
{
new StoredStateIsNullCon<LastOpenedStorageState, IEntity>(
new InverseBoolCurve()),
new DistanceCon(
new QuadraticCurve(-1.0f, 1.0f, 1.02f, 0.0f)),
};
public override void SetupOperators(Blackboard context) public override void SetupOperators(Blackboard context)
{ {
var lastStorage = context.GetState<LastOpenedStorageState>().GetValue(); var lastStorage = context.GetState<LastOpenedStorageState>().GetValue();
@@ -37,6 +31,21 @@ namespace Content.Server.AI.Utility.Actions.Idle
new MoveToEntityOperator(Owner, lastStorage), new MoveToEntityOperator(Owner, lastStorage),
new CloseLastStorageOperator(Owner), new CloseLastStorageOperator(Owner),
}); });
}
protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
{
var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
return new[]
{
considerationsManager.Get<StoredStateEntityIsNullCon>().Set(typeof(LastOpenedStorageState), context)
.InverseBoolCurve(context),
considerationsManager.Get<DistanceCon>()
.QuadraticCurve(context, 1.0f, 1.0f, 0.02f, 0.0f),
};
} }
} }
} }

View File

@@ -1,10 +1,11 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.AI.Operators; using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Generic; using Content.Server.AI.Operators.Generic;
using Content.Server.AI.Operators.Movement; using Content.Server.AI.Operators.Movement;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.ActionBlocker; using Content.Server.AI.Utility.Considerations.ActionBlocker;
using Content.Server.AI.Utility.Curves; using Content.Server.AI.Utility.Considerations.Containers;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Map; using Robust.Shared.Interfaces.Map;
@@ -22,12 +23,9 @@ namespace Content.Server.AI.Utility.Actions.Idle
public sealed class WanderAndWait : UtilityAction public sealed class WanderAndWait : UtilityAction
{ {
public override bool CanOverride => false; public override bool CanOverride => false;
public override float Bonus => IdleBonus; public override float Bonus => 1.0f;
public WanderAndWait(IEntity owner) : base(owner) public WanderAndWait(IEntity owner) : base(owner) {}
{
// TODO: Need a Success method that gets called to update context (e.g. when we last did X)
}
public override void SetupOperators(Blackboard context) public override void SetupOperators(Blackboard context)
{ {
@@ -49,12 +47,18 @@ namespace Content.Server.AI.Utility.Actions.Idle
new WaitOperator(waitTime), new WaitOperator(waitTime),
}); });
} }
protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
{
var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
protected override Consideration[] Considerations { get; } = { return new[]
new CanMoveCon( {
new BoolCurve()) considerationsManager.Get<CanMoveCon>()
// Last wander? If we also want to sit still .BoolCurve(context),
};
};
}
private GridCoordinates FindRandomGrid() private GridCoordinates FindRandomGrid()
{ {

View File

@@ -1,13 +1,15 @@
using System;
using System.Collections.Generic;
using Content.Server.AI.Operators.Sequences; using Content.Server.AI.Operators.Sequences;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Containers; using Content.Server.AI.Utility.Considerations.Containers;
using Content.Server.AI.Utility.Considerations.Hands; using Content.Server.AI.Utility.Considerations.Hands;
using Content.Server.AI.Utility.Considerations.Movement; using Content.Server.AI.Utility.Considerations.Movement;
using Content.Server.AI.Utility.Considerations.Nutrition.Drink; using Content.Server.AI.Utility.Considerations.Nutrition.Drink;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Nutrition.Drink namespace Content.Server.AI.Utility.Actions.Nutrition.Drink
{ {
@@ -25,25 +27,31 @@ namespace Content.Server.AI.Utility.Actions.Nutrition.Drink
{ {
ActionOperators = new GoPickupEntitySequence(Owner, _entity).Sequence; ActionOperators = new GoPickupEntitySequence(Owner, _entity).Sequence;
} }
protected override Consideration[] Considerations => new Consideration[]
{
new TargetAccessibleCon(
new BoolCurve()),
new FreeHandCon(
new BoolCurve()),
new ThirstCon(
new LogisticCurve(1000f, 1.3f, -1.0f, 0.5f)),
new DistanceCon(
new QuadraticCurve(-1.0f, 1.0f, 1.02f, 0.0f)),
new DrinkValueCon(
new QuadraticCurve(1.0f, 0.4f, 0.0f, 0.0f)),
};
protected override void UpdateBlackboard(Blackboard context) protected override void UpdateBlackboard(Blackboard context)
{ {
base.UpdateBlackboard(context); base.UpdateBlackboard(context);
context.GetState<TargetEntityState>().SetValue(_entity); context.GetState<TargetEntityState>().SetValue(_entity);
} }
protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
{
var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
return new[]
{
considerationsManager.Get<TargetAccessibleCon>()
.BoolCurve(context),
considerationsManager.Get<FreeHandCon>()
.BoolCurve(context),
considerationsManager.Get<ThirstCon>()
.LogisticCurve(context, 1000f, 1.3f, -1.0f, 0.5f),
considerationsManager.Get<DistanceCon>()
.QuadraticCurve(context, 1.0f, 1.0f, 0.02f, 0.0f),
considerationsManager.Get<DrinkValueCon>()
.QuadraticCurve(context, 1.0f, 0.4f, 0.0f, 0.0f),
};
}
} }
} }

View File

@@ -1,13 +1,14 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.AI.Operators; using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Inventory; using Content.Server.AI.Operators.Inventory;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Hands; using Content.Server.AI.Utility.Considerations.Hands;
using Content.Server.AI.Utility.Considerations.Nutrition.Drink; using Content.Server.AI.Utility.Considerations.Nutrition.Drink;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Nutrition.Drink namespace Content.Server.AI.Utility.Actions.Nutrition.Drink
{ {
@@ -29,21 +30,26 @@ namespace Content.Server.AI.Utility.Actions.Nutrition.Drink
new UseItemInHandsOperator(Owner, _entity), new UseItemInHandsOperator(Owner, _entity),
}); });
} }
protected override Consideration[] Considerations => new Consideration[]
{
new TargetInOurHandsCon(
new BoolCurve()),
new ThirstCon(
new LogisticCurve(1000f, 1.3f, -0.3f, 0.5f)),
new DrinkValueCon(
new QuadraticCurve(1.0f, 0.4f, 0.0f, 0.0f))
};
protected override void UpdateBlackboard(Blackboard context) protected override void UpdateBlackboard(Blackboard context)
{ {
base.UpdateBlackboard(context); base.UpdateBlackboard(context);
context.GetState<TargetEntityState>().SetValue(_entity); context.GetState<TargetEntityState>().SetValue(_entity);
}
protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
{
var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
return new[]
{
considerationsManager.Get<TargetInOurHandsCon>()
.BoolCurve(context),
considerationsManager.Get<ThirstCon>()
.LogisticCurve(context, 1000f, 1.3f, -0.3f, 0.5f),
considerationsManager.Get<DrinkValueCon>()
.QuadraticCurve(context, 1.0f, 0.4f, 0.0f, 0.0f),
};
} }
} }
} }

View File

@@ -1,13 +1,15 @@
using System;
using System.Collections.Generic;
using Content.Server.AI.Operators.Sequences; using Content.Server.AI.Operators.Sequences;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Containers; using Content.Server.AI.Utility.Considerations.Containers;
using Content.Server.AI.Utility.Considerations.Hands; using Content.Server.AI.Utility.Considerations.Hands;
using Content.Server.AI.Utility.Considerations.Movement; using Content.Server.AI.Utility.Considerations.Movement;
using Content.Server.AI.Utility.Considerations.Nutrition; using Content.Server.AI.Utility.Considerations.Nutrition.Food;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Nutrition.Food namespace Content.Server.AI.Utility.Actions.Nutrition.Food
{ {
@@ -26,24 +28,29 @@ namespace Content.Server.AI.Utility.Actions.Nutrition.Food
ActionOperators = new GoPickupEntitySequence(Owner, _entity).Sequence; ActionOperators = new GoPickupEntitySequence(Owner, _entity).Sequence;
} }
protected override Consideration[] Considerations => new Consideration[]
{
new TargetAccessibleCon(
new BoolCurve()),
new FreeHandCon(
new BoolCurve()),
new HungerCon(
new LogisticCurve(1000f, 1.3f, -1.0f, 0.5f)),
new DistanceCon(
new QuadraticCurve(-1.0f, 1.0f, 1.02f, 0.0f)),
new FoodValueCon(
new QuadraticCurve(1.0f, 0.4f, 0.0f, 0.0f)),
};
protected override void UpdateBlackboard(Blackboard context) protected override void UpdateBlackboard(Blackboard context)
{ {
base.UpdateBlackboard(context); base.UpdateBlackboard(context);
context.GetState<TargetEntityState>().SetValue(_entity); context.GetState<TargetEntityState>().SetValue(_entity);
}
protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
{
var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
return new[]
{
considerationsManager.Get<TargetAccessibleCon>()
.BoolCurve(context),
considerationsManager.Get<FreeHandCon>()
.BoolCurve(context),
considerationsManager.Get<HungerCon>()
.LogisticCurve(context, 1000f, 1.3f, -1.0f, 0.5f),
considerationsManager.Get<DistanceCon>()
.QuadraticCurve(context, 1.0f, 1.0f, 0.02f, 0.0f),
considerationsManager.Get<FoodValueCon>()
.QuadraticCurve(context, 1.0f, 0.4f, 0.0f, 0.0f),
};
} }
} }
} }

View File

@@ -1,13 +1,15 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.AI.Operators; using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Inventory; using Content.Server.AI.Operators.Inventory;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Considerations.Containers;
using Content.Server.AI.Utility.Considerations.Hands; using Content.Server.AI.Utility.Considerations.Hands;
using Content.Server.AI.Utility.Considerations.Nutrition; using Content.Server.AI.Utility.Considerations.Nutrition.Food;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Actions.Nutrition.Food namespace Content.Server.AI.Utility.Actions.Nutrition.Food
{ {
@@ -30,20 +32,26 @@ namespace Content.Server.AI.Utility.Actions.Nutrition.Food
}); });
} }
protected override Consideration[] Considerations => new Consideration[]
{
new TargetInOurHandsCon(
new BoolCurve()),
new HungerCon(
new LogisticCurve(1000f, 1.3f, -0.3f, 0.5f)),
new FoodValueCon(
new QuadraticCurve(1.0f, 0.4f, 0.0f, 0.0f))
};
protected override void UpdateBlackboard(Blackboard context) protected override void UpdateBlackboard(Blackboard context)
{ {
base.UpdateBlackboard(context); base.UpdateBlackboard(context);
context.GetState<TargetEntityState>().SetValue(_entity); context.GetState<TargetEntityState>().SetValue(_entity);
}
protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
{
var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
return new[]
{
considerationsManager.Get<TargetInOurHandsCon>()
.BoolCurve(context),
considerationsManager.Get<HungerCon>()
.LogisticCurve(context, 1000f, 1.3f, -0.3f, 0.5f),
considerationsManager.Get<FoodValueCon>()
.QuadraticCurve(context, 1.0f, 0.4f, 0.0f, 0.0f),
};
} }
} }
} }

View File

@@ -1,10 +1,11 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.AI.Operators; using Content.Server.AI.Operators;
using Content.Server.AI.Operators.Movement; using Content.Server.AI.Operators.Movement;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Maths; using Robust.Shared.Maths;
namespace Content.Server.AI.Utility.Actions.Test namespace Content.Server.AI.Utility.Actions.Test
@@ -18,11 +19,6 @@ namespace Content.Server.AI.Utility.Actions.Test
public MoveRightAndLeftTen(IEntity owner) : base(owner) {} public MoveRightAndLeftTen(IEntity owner) : base(owner) {}
protected override Consideration[] Considerations { get; } = {
new DummyCon(
new BoolCurve())
};
public override void SetupOperators(Blackboard context) public override void SetupOperators(Blackboard context)
{ {
var currentPosition = Owner.Transform.GridPosition; var currentPosition = Owner.Transform.GridPosition;
@@ -36,5 +32,16 @@ namespace Content.Server.AI.Utility.Actions.Test
originalPosOp originalPosOp
}); });
} }
protected override IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context)
{
var considerationsManager = IoCManager.Resolve<ConsiderationsManager>();
return new[]
{
considerationsManager.Get<DummyCon>()
.BoolCurve(context),
};
}
} }
} }

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using Content.Server.AI.Operators; using Content.Server.AI.Operators;
using Content.Server.AI.Utility.Considerations; using Content.Server.AI.Utility.Considerations;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States.Utility;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Utility; using Robust.Shared.Utility;
@@ -42,7 +43,9 @@ namespace Content.Server.AI.Utility.Actions
/// All the considerations are multiplied together to get the final score; a consideration of 0.0 means the action is not possible. /// All the considerations are multiplied together to get the final score; a consideration of 0.0 means the action is not possible.
/// Ideally you put anything that's easy to assess and can cause an early-out first just so the rest aren't evaluated. /// Ideally you put anything that's easy to assess and can cause an early-out first just so the rest aren't evaluated.
/// </summary> /// </summary>
protected abstract Consideration[] Considerations { get; } /// Uses Func<float> as you don't want to eval the later considerations unless necessary, but we also need the total count
/// so can't use IEnumerable
protected abstract IReadOnlyCollection<Func<float>> GetConsiderations(Blackboard context);
/// <summary> /// <summary>
/// To keep the operators simple we can chain them together here, e.g. move to can be chained with other operators. /// To keep the operators simple we can chain them together here, e.g. move to can be chained with other operators.
@@ -109,7 +112,8 @@ namespace Content.Server.AI.Utility.Actions
public float GetScore(Blackboard context, float min) public float GetScore(Blackboard context, float min)
{ {
UpdateBlackboard(context); UpdateBlackboard(context);
DebugTools.Assert(Considerations.Length > 0); var considerations = GetConsiderations(context);
DebugTools.Assert(considerations.Count > 0);
// I used the IAUS video although I did have some confusion on how to structure it overall // I used the IAUS video although I did have some confusion on how to structure it overall
// as some of the slides seemed contradictory // as some of the slides seemed contradictory
@@ -121,19 +125,14 @@ namespace Content.Server.AI.Utility.Actions
// 23:00 Building a better centaur // 23:00 Building a better centaur
var finalScore = 1.0f; var finalScore = 1.0f;
var minThreshold = min / Bonus; var minThreshold = min / Bonus;
var modificationFactor = 1.0f - 1.0f / Considerations.Length; context.GetState<ConsiderationState>().SetValue(considerations.Count);
// See 10:09 for this and the adjustments // See 10:09 for this and the adjustments
foreach (var consideration in Considerations) foreach (var consideration in considerations)
{ {
var score = consideration.GetScore(context); var score = consideration.Invoke();
var makeUpValue = (1.0f - score) * modificationFactor; finalScore *= score;
var adjustedScore = score + makeUpValue * score; DebugTools.Assert(!float.IsNaN(score));
var response = consideration.ComputeResponseCurve(adjustedScore);
finalScore *= response;
DebugTools.Assert(!float.IsNaN(response));
// The score can only ever go down from each consideration so if we're below minimum no point continuing. // The score can only ever go down from each consideration so if we're below minimum no point continuing.
if (0.0f >= finalScore || finalScore < minThreshold) { if (0.0f >= finalScore || finalScore < minThreshold) {

View File

@@ -13,6 +13,7 @@ using Content.Server.GameObjects.EntitySystems.JobQueues;
using Robust.Server.AI; using Robust.Server.AI;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Utility; using Robust.Shared.Utility;
namespace Content.Server.AI.Utility.AiLogic namespace Content.Server.AI.Utility.AiLogic
@@ -147,6 +148,14 @@ namespace Content.Server.AI.Utility.AiLogic
private void ReceivedAction() private void ReceivedAction()
{ {
switch (_actionRequest.Exception)
{
case null:
break;
default:
Logger.FatalS("ai", _actionRequest.Exception.ToString());
throw _actionRequest.Exception;
}
var action = _actionRequest.Result; var action = _actionRequest.Result;
_actionRequest = null; _actionRequest = null;
// Actions with lower scores should be implicitly dumped by GetAction // Actions with lower scores should be implicitly dumped by GetAction

View File

@@ -1,4 +1,3 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems;
@@ -9,9 +8,7 @@ namespace Content.Server.AI.Utility.Considerations.ActionBlocker
{ {
public sealed class CanMoveCon : Consideration public sealed class CanMoveCon : Consideration
{ {
public CanMoveCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
var self = context.GetState<SelfState>().GetValue(); var self = context.GetState<SelfState>().GetValue();
if (!ActionBlockerSystem.CanMove(self)) if (!ActionBlockerSystem.CanMove(self))

View File

@@ -1,5 +1,5 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States.Clothing;
using Content.Server.AI.WorldState.States.Inventory; using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.GameObjects; using Content.Server.GameObjects;
using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Inventory;
@@ -8,25 +8,27 @@ namespace Content.Server.AI.Utility.Considerations.Clothing
{ {
public sealed class ClothingInInventoryCon : Consideration public sealed class ClothingInInventoryCon : Consideration
{ {
private readonly EquipmentSlotDefines.SlotFlags _slot; public ClothingInInventoryCon Slot(EquipmentSlotDefines.SlotFlags slotFlags, Blackboard context)
public ClothingInInventoryCon(EquipmentSlotDefines.SlotFlags slotFlags, IResponseCurve curve) : base(curve)
{ {
_slot = slotFlags; // Ideally we'd just use a variable but then if we were iterating through multiple AI at once it'd be
// Stuffed so we need to store it on the AI's context.
context.GetState<ClothingSlotFlagConState>().SetValue(slotFlags);
return this;
} }
public override float GetScore(Blackboard context) protected override float GetScore(Blackboard context)
{ {
var inventory = context.GetState<InventoryState>().GetValue(); var slots = context.GetState<ClothingSlotConState>().GetValue();
var slotFlags = EquipmentSlotDefines.SlotMasks[slots];
foreach (var entity in inventory) foreach (var entity in context.GetState<EnumerableInventoryState>().GetValue())
{ {
if (!entity.TryGetComponent(out ClothingComponent clothingComponent)) if (!entity.TryGetComponent(out ClothingComponent clothingComponent))
{ {
continue; continue;
} }
if ((clothingComponent.SlotFlags & _slot) != 0) if ((clothingComponent.SlotFlags & slotFlags) != 0)
{ {
return 1.0f; return 1.0f;
} }

View File

@@ -1,4 +1,3 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States.Clothing; using Content.Server.AI.WorldState.States.Clothing;
using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Inventory;
@@ -7,18 +6,18 @@ namespace Content.Server.AI.Utility.Considerations.Clothing
{ {
public class ClothingInSlotCon : Consideration public class ClothingInSlotCon : Consideration
{ {
private EquipmentSlotDefines.Slots _slot;
public ClothingInSlotCon(EquipmentSlotDefines.Slots slot, IResponseCurve curve) : base(curve) public ClothingInSlotCon Slot(EquipmentSlotDefines.Slots slot, Blackboard context)
{ {
_slot = slot; context.GetState<ClothingSlotConState>().SetValue(slot);
return this;
} }
public override float GetScore(Blackboard context) protected override float GetScore(Blackboard context)
{ {
var slot = context.GetState<ClothingSlotConState>().GetValue();
var inventory = context.GetState<EquippedClothingState>().GetValue(); var inventory = context.GetState<EquippedClothingState>().GetValue();
return inventory.ContainsKey(slot) ? 1.0f : 0.0f;
return inventory.ContainsKey(_slot) ? 1.0f : 0.0f;
} }
} }
} }

View File

@@ -1,4 +1,3 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects.Components.Weapon.Melee; using Content.Server.GameObjects.Components.Weapon.Melee;
@@ -7,9 +6,7 @@ namespace Content.Server.AI.Utility.Considerations.Combat.Melee
{ {
public sealed class CanUnarmedCombatCon : Consideration public sealed class CanUnarmedCombatCon : Consideration
{ {
public CanUnarmedCombatCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
return context.GetState<SelfState>().GetValue().HasComponent<UnarmedCombatComponent>() ? 1.0f : 0.0f; return context.GetState<SelfState>().GetValue().HasComponent<UnarmedCombatComponent>() ? 1.0f : 0.0f;
} }

View File

@@ -1,4 +1,3 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States.Inventory; using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.GameObjects.Components.Weapon.Melee; using Content.Server.GameObjects.Components.Weapon.Melee;
@@ -7,11 +6,9 @@ namespace Content.Server.AI.Utility.Considerations.Combat.Melee
{ {
public sealed class HasMeleeWeaponCon : Consideration public sealed class HasMeleeWeaponCon : Consideration
{ {
public HasMeleeWeaponCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
foreach (var item in context.GetState<InventoryState>().GetValue()) foreach (var item in context.GetState<EnumerableInventoryState>().GetValue())
{ {
if (item.HasComponent<MeleeWeaponComponent>()) if (item.HasComponent<MeleeWeaponComponent>())
{ {

View File

@@ -1,4 +1,3 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States.Combat; using Content.Server.AI.WorldState.States.Combat;
using Content.Server.GameObjects.Components.Weapon.Melee; using Content.Server.GameObjects.Components.Weapon.Melee;
@@ -7,9 +6,7 @@ namespace Content.Server.AI.Utility.Considerations.Combat.Melee
{ {
public sealed class MeleeWeaponDamageCon : Consideration public sealed class MeleeWeaponDamageCon : Consideration
{ {
public MeleeWeaponDamageCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
var target = context.GetState<WeaponEntityState>().GetValue(); var target = context.GetState<WeaponEntityState>().GetValue();

View File

@@ -1,4 +1,3 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States.Inventory; using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.GameObjects.Components.Weapon.Melee; using Content.Server.GameObjects.Components.Weapon.Melee;
@@ -7,9 +6,7 @@ namespace Content.Server.AI.Utility.Considerations.Combat.Melee
{ {
public sealed class MeleeWeaponEquippedCon : Consideration public sealed class MeleeWeaponEquippedCon : Consideration
{ {
public MeleeWeaponEquippedCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
var equipped = context.GetState<EquippedEntityState>().GetValue(); var equipped = context.GetState<EquippedEntityState>().GetValue();

View File

@@ -1,4 +1,3 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States.Combat; using Content.Server.AI.WorldState.States.Combat;
using Content.Server.GameObjects.Components.Weapon.Melee; using Content.Server.GameObjects.Components.Weapon.Melee;
@@ -7,9 +6,7 @@ namespace Content.Server.AI.Utility.Considerations.Combat.Melee
{ {
public sealed class MeleeWeaponSpeedCon : Consideration public sealed class MeleeWeaponSpeedCon : Consideration
{ {
public MeleeWeaponSpeedCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
var target = context.GetState<WeaponEntityState>().GetValue(); var target = context.GetState<WeaponEntityState>().GetValue();

View File

@@ -1,4 +1,3 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects; using Content.Server.GameObjects;
@@ -8,9 +7,7 @@ namespace Content.Server.AI.Utility.Considerations.Combat
{ {
public sealed class TargetHealthCon : Consideration public sealed class TargetHealthCon : Consideration
{ {
public TargetHealthCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
var target = context.GetState<TargetEntityState>().GetValue(); var target = context.GetState<TargetEntityState>().GetValue();

View File

@@ -1,16 +1,12 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects; using Content.Server.GameObjects;
using Content.Shared.GameObjects;
namespace Content.Server.AI.Utility.Considerations.Combat namespace Content.Server.AI.Utility.Considerations.Combat
{ {
public sealed class TargetIsCritCon : Consideration public sealed class TargetIsCritCon : Consideration
{ {
public TargetIsCritCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
var target = context.GetState<TargetEntityState>().GetValue(); var target = context.GetState<TargetEntityState>().GetValue();

View File

@@ -1,4 +1,3 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects; using Content.Server.GameObjects;
@@ -7,9 +6,7 @@ namespace Content.Server.AI.Utility.Considerations.Combat
{ {
public sealed class TargetIsDeadCon : Consideration public sealed class TargetIsDeadCon : Consideration
{ {
public TargetIsDeadCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
var target = context.GetState<TargetEntityState>().GetValue(); var target = context.GetState<TargetEntityState>().GetValue();

View File

@@ -1,25 +1,67 @@
using System; using System;
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States.Utility;
namespace Content.Server.AI.Utility.Considerations namespace Content.Server.AI.Utility.Considerations
{ {
public abstract class Consideration public abstract class Consideration
{ {
protected IResponseCurve Curve { get; } protected abstract float GetScore(Blackboard context);
public Consideration(IResponseCurve curve) private float GetAdjustedScore(Blackboard context)
{ {
Curve = curve; var score = GetScore(context);
var considerationsCount = context.GetState<ConsiderationState>().GetValue();
var modificationFactor = 1.0f - 1.0f / considerationsCount;
var makeUpValue = (1.0f - score) * modificationFactor;
var adjustedScore = score + makeUpValue * score;
return Math.Clamp(adjustedScore, 0.0f, 1.0f);
} }
public abstract float GetScore(Blackboard context); public Func<float> BoolCurve(Blackboard context)
public float ComputeResponseCurve(float score)
{ {
var clampedScore = Math.Clamp(score, 0.0f, 1.0f); float Result()
var curvedResponse = Math.Clamp(Curve.GetResponse(clampedScore), 0.0f, 1.0f); {
return curvedResponse; var adjustedScore = GetAdjustedScore(context);
// ReSharper disable once CompareOfFloatsByEqualityOperator
return adjustedScore == 1.0f ? 1.0f : 0.0f;
}
return Result;
}
public Func<float> InverseBoolCurve(Blackboard context)
{
float Result()
{
var adjustedScore = GetAdjustedScore(context);
// ReSharper disable once CompareOfFloatsByEqualityOperator
return adjustedScore == 1.0f ? 0.0f : 1.0f;
}
return Result;
}
public Func<float> LogisticCurve(Blackboard context, float slope, float exponent, float yOffset, float xOffset)
{
float Result()
{
var adjustedScore = GetAdjustedScore(context);
return Math.Clamp(exponent * (1 / (1 + (float) Math.Pow(Math.Log(1000) * slope, -1 * adjustedScore + xOffset))) + yOffset, 0.0f, 1.0f);
}
return Result;
}
public Func<float> QuadraticCurve(Blackboard context, float slope, float exponent, float yOffset, float xOffset)
{
float Result()
{
var adjustedScore = GetAdjustedScore(context);
return Math.Clamp(slope * (float) Math.Pow(adjustedScore - xOffset, exponent) + yOffset, 0.0f, 1.0f);
}
return Result;
} }
} }
} }

View File

@@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using Robust.Shared.Interfaces.Reflection;
using Robust.Shared.IoC;
namespace Content.Server.AI.Utility.Considerations
{
public class ConsiderationsManager
{
private Dictionary<Type, Consideration> _considerations = new Dictionary<Type, Consideration>();
public void Initialize()
{
var reflectionManager = IoCManager.Resolve<IReflectionManager>();
var typeFactory = IoCManager.Resolve<IDynamicTypeFactory>();
foreach (var conType in reflectionManager.GetAllChildren(typeof(Consideration)))
{
var con = (Consideration) typeFactory.CreateInstance(conType);
_considerations.Add(conType, con);
}
}
public T Get<T>() where T : Consideration
{
return (T) _considerations[typeof(T)];
}
}
}

View File

@@ -1,7 +1,5 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects;
using Content.Server.GameObjects.Components; using Content.Server.GameObjects.Components;
using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Items.Storage;
using Robust.Shared.Containers; using Robust.Shared.Containers;
@@ -13,9 +11,7 @@ namespace Content.Server.AI.Utility.Considerations.Containers
/// </summary> /// </summary>
public sealed class TargetAccessibleCon : Consideration public sealed class TargetAccessibleCon : Consideration
{ {
public TargetAccessibleCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
var target = context.GetState<TargetEntityState>().GetValue(); var target = context.GetState<TargetEntityState>().GetValue();
if (target == null) if (target == null)

View File

@@ -1,12 +1,9 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
namespace Content.Server.AI.Utility.Considerations namespace Content.Server.AI.Utility.Considerations
{ {
public class DummyCon : Consideration public class DummyCon : Consideration
{ {
public DummyCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context) => 1.0f;
public override float GetScore(Blackboard context) => 1.0f;
} }
} }

View File

@@ -1,4 +1,3 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects; using Content.Server.GameObjects;
@@ -7,9 +6,7 @@ namespace Content.Server.AI.Utility.Considerations.Hands
{ {
public class FreeHandCon : Consideration public class FreeHandCon : Consideration
{ {
public FreeHandCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
var owner = context.GetState<SelfState>().GetValue(); var owner = context.GetState<SelfState>().GetValue();

View File

@@ -1,4 +1,3 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects; using Content.Server.GameObjects;
@@ -11,9 +10,7 @@ namespace Content.Server.AI.Utility.Considerations.Hands
/// </summary> /// </summary>
public sealed class TargetInOurHandsCon : Consideration public sealed class TargetInOurHandsCon : Consideration
{ {
public TargetInOurHandsCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
var owner = context.GetState<SelfState>().GetValue(); var owner = context.GetState<SelfState>().GetValue();
var target = context.GetState<TargetEntityState>().GetValue(); var target = context.GetState<TargetEntityState>().GetValue();

View File

@@ -1,4 +1,3 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Hands; using Content.Server.AI.WorldState.States.Hands;
@@ -9,9 +8,7 @@ namespace Content.Server.AI.Utility.Considerations.Inventory
{ {
public class CanPutTargetInHandsCon : Consideration public class CanPutTargetInHandsCon : Consideration
{ {
public CanPutTargetInHandsCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
// First check if target in inventory already // First check if target in inventory already
// If not then check if we have a free hand // If not then check if we have a free hand
@@ -22,9 +19,7 @@ namespace Content.Server.AI.Utility.Considerations.Inventory
return 0.0f; return 0.0f;
} }
var inventory = context.GetState<InventoryState>().GetValue(); foreach (var item in context.GetState<EnumerableInventoryState>().GetValue())
foreach (var item in inventory)
{ {
if (item == target) if (item == target)
{ {

View File

@@ -1,4 +1,3 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Inventory; using Content.Server.AI.WorldState.States.Inventory;
@@ -8,11 +7,8 @@ namespace Content.Server.AI.Utility.Considerations.Inventory
{ {
public class TargetInOurInventoryCon : Consideration public class TargetInOurInventoryCon : Consideration
{ {
public TargetInOurInventoryCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
var inventory = context.GetState<InventoryState>().GetValue();
var target = context.GetState<TargetEntityState>().GetValue(); var target = context.GetState<TargetEntityState>().GetValue();
if (target == null || !target.HasComponent<ItemComponent>()) if (target == null || !target.HasComponent<ItemComponent>())
@@ -20,7 +16,7 @@ namespace Content.Server.AI.Utility.Considerations.Inventory
return 0.0f; return 0.0f;
} }
foreach (var item in inventory) foreach (var item in context.GetState<EnumerableInventoryState>().GetValue())
{ {
if (item == target) if (item == target)
{ {

View File

@@ -1,4 +1,3 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
@@ -6,9 +5,7 @@ namespace Content.Server.AI.Utility.Considerations.Movement
{ {
public sealed class DistanceCon : Consideration public sealed class DistanceCon : Consideration
{ {
public DistanceCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
var self = context.GetState<SelfState>().GetValue(); var self = context.GetState<SelfState>().GetValue();
var target = context.GetState<TargetEntityState>().GetValue(); var target = context.GetState<TargetEntityState>().GetValue();

View File

@@ -1,4 +1,3 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects.Components.Chemistry; using Content.Server.GameObjects.Components.Chemistry;
@@ -7,9 +6,7 @@ namespace Content.Server.AI.Utility.Considerations.Nutrition.Drink
{ {
public sealed class DrinkValueCon : Consideration public sealed class DrinkValueCon : Consideration
{ {
public DrinkValueCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
var target = context.GetState<TargetEntityState>().GetValue(); var target = context.GetState<TargetEntityState>().GetValue();

View File

@@ -1,4 +1,3 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects.Components.Nutrition; using Content.Server.GameObjects.Components.Nutrition;
@@ -8,9 +7,7 @@ namespace Content.Server.AI.Utility.Considerations.Nutrition.Drink
{ {
public class ThirstCon : Consideration public class ThirstCon : Consideration
{ {
public ThirstCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
var owner = context.GetState<SelfState>().GetValue(); var owner = context.GetState<SelfState>().GetValue();

View File

@@ -1,15 +1,12 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects.Components.Chemistry; using Content.Server.GameObjects.Components.Chemistry;
namespace Content.Server.AI.Utility.Considerations.Nutrition namespace Content.Server.AI.Utility.Considerations.Nutrition.Food
{ {
public sealed class FoodValueCon : Consideration public sealed class FoodValueCon : Consideration
{ {
public FoodValueCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
var target = context.GetState<TargetEntityState>().GetValue(); var target = context.GetState<TargetEntityState>().GetValue();

View File

@@ -1,17 +1,14 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.GameObjects.Components.Nutrition; using Content.Server.GameObjects.Components.Nutrition;
using Content.Shared.GameObjects.Components.Nutrition; using Content.Shared.GameObjects.Components.Nutrition;
namespace Content.Server.AI.Utility.Considerations.Nutrition namespace Content.Server.AI.Utility.Considerations.Nutrition.Food
{ {
public sealed class HungerCon : Consideration public sealed class HungerCon : Consideration
{ {
public HungerCon(IResponseCurve curve) : base(curve) {} protected override float GetScore(Blackboard context)
public override float GetScore(Blackboard context)
{ {
var owner = context.GetState<SelfState>().GetValue(); var owner = context.GetState<SelfState>().GetValue();

View File

@@ -0,0 +1,26 @@
using System;
using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States.Utility;
namespace Content.Server.AI.Utility.Considerations.State
{
/// <summary>
/// Simple NullCheck on a StoredState
/// </summary>
public sealed class StoredStateEntityIsNullCon : Consideration
{
public StoredStateEntityIsNullCon Set(Type type, Blackboard context)
{
// Ideally we'd just use a variable but then if we were iterating through multiple AI at once it'd be
// Stuffed so we need to store it on the AI's context.
context.GetState<StoredStateIsNullState>().SetValue(type);
return this;
}
protected override float GetScore(Blackboard context)
{
var stateData = context.GetState<StoredStateIsNullState>().GetValue();
return stateData == null ? 1.0f : 0.0f;
}
}
}

View File

@@ -1,24 +0,0 @@
using Content.Server.AI.Utility.Curves;
using Content.Server.AI.WorldState;
namespace Content.Server.AI.Utility.Considerations.State
{
/// <summary>
/// Simple NullCheck on a StoredState
/// </summary>
public sealed class StoredStateIsNullCon<T, U> : Consideration where T : StoredStateData<U>
{
public StoredStateIsNullCon(IResponseCurve curve) : base(curve) {}
public override float GetScore(Blackboard context)
{
var state = context.GetState<T>();
if (state.GetValue() == null)
{
return 1.0f;
}
return 0.0f;
}
}
}

View File

@@ -21,12 +21,8 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Gloves
public override IEnumerable<UtilityAction> GetActions(Blackboard context) public override IEnumerable<UtilityAction> GetActions(Blackboard context)
{ {
var owner = context.GetState<SelfState>().GetValue(); var owner = context.GetState<SelfState>().GetValue();
if (!owner.TryGetComponent(out AiControllerComponent controller))
{
throw new InvalidOperationException();
}
foreach (var entity in context.GetState<InventoryState>().GetValue()) foreach (var entity in context.GetState<EnumerableInventoryState>().GetValue())
{ {
if (entity.TryGetComponent(out ClothingComponent clothing) && if (entity.TryGetComponent(out ClothingComponent clothing) &&
(clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.GLOVES) != 0) (clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.GLOVES) != 0)

View File

@@ -20,7 +20,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Head
{ {
var owner = context.GetState<SelfState>().GetValue(); var owner = context.GetState<SelfState>().GetValue();
foreach (var entity in context.GetState<InventoryState>().GetValue()) foreach (var entity in context.GetState<EnumerableInventoryState>().GetValue())
{ {
if (entity.TryGetComponent(out ClothingComponent clothing) && if (entity.TryGetComponent(out ClothingComponent clothing) &&
(clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.HEAD) != 0) (clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.HEAD) != 0)

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.AI.Utility.Actions; using Content.Server.AI.Utility.Actions;
using Content.Server.AI.Utility.Actions.Clothing.Head; using Content.Server.AI.Utility.Actions.Clothing.Head;
@@ -5,6 +6,7 @@ using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Clothing; using Content.Server.AI.WorldState.States.Clothing;
using Content.Server.GameObjects; using Content.Server.GameObjects;
using Content.Server.GameObjects.Components.Movement;
using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Inventory;
namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Head namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Head
@@ -16,6 +18,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Head
public override IEnumerable<UtilityAction> GetActions(Blackboard context) public override IEnumerable<UtilityAction> GetActions(Blackboard context)
{ {
var owner = context.GetState<SelfState>().GetValue(); var owner = context.GetState<SelfState>().GetValue();
foreach (var entity in context.GetState<NearbyClothingState>().GetValue()) foreach (var entity in context.GetState<NearbyClothingState>().GetValue())
{ {
if (entity.TryGetComponent(out ClothingComponent clothing) && if (entity.TryGetComponent(out ClothingComponent clothing) &&

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.AI.Utility.Actions; using Content.Server.AI.Utility.Actions;
using Content.Server.AI.Utility.Actions.Clothing.OuterClothing; using Content.Server.AI.Utility.Actions.Clothing.OuterClothing;
@@ -5,6 +6,7 @@ using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Inventory; using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.GameObjects; using Content.Server.GameObjects;
using Content.Server.GameObjects.Components.Movement;
using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Inventory;
namespace Content.Server.AI.Utility.ExpandableActions.Clothing.OuterClothing namespace Content.Server.AI.Utility.ExpandableActions.Clothing.OuterClothing
@@ -20,7 +22,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.OuterClothing
{ {
var owner = context.GetState<SelfState>().GetValue(); var owner = context.GetState<SelfState>().GetValue();
foreach (var entity in context.GetState<InventoryState>().GetValue()) foreach (var entity in context.GetState<EnumerableInventoryState>().GetValue())
{ {
if (entity.TryGetComponent(out ClothingComponent clothing) && if (entity.TryGetComponent(out ClothingComponent clothing) &&
(clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.OUTERCLOTHING) != 0) (clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.OUTERCLOTHING) != 0)

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.AI.Utility.Actions; using Content.Server.AI.Utility.Actions;
using Content.Server.AI.Utility.Actions.Clothing.Shoes; using Content.Server.AI.Utility.Actions.Clothing.Shoes;
@@ -5,6 +6,7 @@ using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Inventory; using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.GameObjects; using Content.Server.GameObjects;
using Content.Server.GameObjects.Components.Movement;
using Content.Shared.GameObjects.Components.Inventory; using Content.Shared.GameObjects.Components.Inventory;
namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Shoes namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Shoes
@@ -20,7 +22,7 @@ namespace Content.Server.AI.Utility.ExpandableActions.Clothing.Shoes
{ {
var owner = context.GetState<SelfState>().GetValue(); var owner = context.GetState<SelfState>().GetValue();
foreach (var entity in context.GetState<InventoryState>().GetValue()) foreach (var entity in context.GetState<EnumerableInventoryState>().GetValue())
{ {
if (entity.TryGetComponent(out ClothingComponent clothing) && if (entity.TryGetComponent(out ClothingComponent clothing) &&
(clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.SHOES) != 0) (clothing.SlotFlags & EquipmentSlotDefines.SlotFlags.SHOES) != 0)

View File

@@ -4,6 +4,7 @@ using Content.Server.AI.Utility.Actions.Combat.Melee;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Inventory; using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.GameObjects.Components.Weapon.Melee;
namespace Content.Server.AI.Utility.ExpandableActions.Combat.Melee namespace Content.Server.AI.Utility.ExpandableActions.Combat.Melee
{ {
@@ -15,8 +16,13 @@ namespace Content.Server.AI.Utility.ExpandableActions.Combat.Melee
{ {
var owner = context.GetState<SelfState>().GetValue(); var owner = context.GetState<SelfState>().GetValue();
foreach (var entity in context.GetState<InventoryState>().GetValue()) foreach (var entity in context.GetState<EnumerableInventoryState>().GetValue())
{ {
if (!entity.HasComponent<MeleeWeaponComponent>())
{
continue;
}
yield return new EquipMelee(owner, entity, Bonus); yield return new EquipMelee(owner, entity, Bonus);
} }
} }

View File

@@ -4,6 +4,7 @@ using Content.Server.AI.Utility.Actions.Nutrition.Drink;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Inventory; using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.GameObjects.Components.Nutrition;
namespace Content.Server.AI.Utility.ExpandableActions.Nutrition namespace Content.Server.AI.Utility.ExpandableActions.Nutrition
{ {
@@ -15,8 +16,13 @@ namespace Content.Server.AI.Utility.ExpandableActions.Nutrition
{ {
var owner = context.GetState<SelfState>().GetValue(); var owner = context.GetState<SelfState>().GetValue();
foreach (var entity in context.GetState<InventoryState>().GetValue()) foreach (var entity in context.GetState<EnumerableInventoryState>().GetValue())
{ {
if (!entity.HasComponent<DrinkComponent>())
{
continue;
}
yield return new UseDrinkInInventory(owner, entity, Bonus); yield return new UseDrinkInInventory(owner, entity, Bonus);
} }
} }

View File

@@ -4,6 +4,7 @@ using Content.Server.AI.Utility.Actions.Nutrition.Food;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
using Content.Server.AI.WorldState.States; using Content.Server.AI.WorldState.States;
using Content.Server.AI.WorldState.States.Inventory; using Content.Server.AI.WorldState.States.Inventory;
using Content.Server.GameObjects.Components.Nutrition;
namespace Content.Server.AI.Utility.ExpandableActions.Nutrition namespace Content.Server.AI.Utility.ExpandableActions.Nutrition
{ {
@@ -15,8 +16,13 @@ namespace Content.Server.AI.Utility.ExpandableActions.Nutrition
{ {
var owner = context.GetState<SelfState>().GetValue(); var owner = context.GetState<SelfState>().GetValue();
foreach (var entity in context.GetState<InventoryState>().GetValue()) foreach (var entity in context.GetState<EnumerableInventoryState>().GetValue())
{ {
if (!entity.HasComponent<FoodComponent>())
{
continue;
}
yield return new UseFoodInInventory(owner, entity, Bonus); yield return new UseFoodInInventory(owner, entity, Bonus);
} }
} }

View File

@@ -56,6 +56,11 @@ namespace Content.Server.AI.WorldState
} }
} }
public void GetState(Type type, out IAiState state)
{
state = _states[type];
}
/// <summary> /// <summary>
/// Get the AI state class /// Get the AI state class
/// </summary> /// </summary>

View File

@@ -1,6 +1,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.Interfaces.GameTicking;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
namespace Content.Server.AI.WorldState namespace Content.Server.AI.WorldState
{ {
@@ -22,6 +25,11 @@ namespace Content.Server.AI.WorldState
void CheckCache(); void CheckCache();
} }
public interface IStoredState
{
}
/// <summary> /// <summary>
/// The default class for state values. Also see CachedStateData and PlanningStateData /// The default class for state values. Also see CachedStateData and PlanningStateData
/// </summary> /// </summary>
@@ -44,7 +52,7 @@ namespace Content.Server.AI.WorldState
/// Useful for group blackboard sharing or to avoid repeating the same action (e.g. bark phrases). /// Useful for group blackboard sharing or to avoid repeating the same action (e.g. bark phrases).
/// </summary> /// </summary>
/// <typeparam name="T"></typeparam> /// <typeparam name="T"></typeparam>
public abstract class StoredStateData<T> : IAiState public abstract class StoredStateData<T> : IAiState, IStoredState
{ {
// Probably not the best class name but couldn't think of anything better // Probably not the best class name but couldn't think of anything better
public abstract string Name { get; } public abstract string Name { get; }
@@ -108,11 +116,11 @@ namespace Content.Server.AI.WorldState
protected IEntity Owner { get; private set; } protected IEntity Owner { get; private set; }
private bool _cached; private bool _cached;
protected T Value; protected T Value;
private DateTime _lastCache = DateTime.Now; private TimeSpan _lastCache = TimeSpan.Zero;
/// <summary> /// <summary>
/// How long something stays in the cache before new values are retrieved /// How long something stays in the cache before new values are retrieved
/// </summary> /// </summary>
protected float CacheTime { get; set; } = 2.0f; protected double CacheTime { get; set; } = 2.0f;
public void Setup(IEntity owner) public void Setup(IEntity owner)
{ {
@@ -121,7 +129,9 @@ namespace Content.Server.AI.WorldState
public void CheckCache() public void CheckCache()
{ {
if (!_cached || (DateTime.Now - _lastCache).TotalSeconds >= CacheTime) var curTime = IoCManager.Resolve<IGameTiming>().CurTime;
if (!_cached || (curTime - _lastCache).TotalSeconds >= CacheTime)
{ {
_cached = false; _cached = false;
return; return;
@@ -142,7 +152,7 @@ namespace Content.Server.AI.WorldState
{ {
Value = GetTrueValue(); Value = GetTrueValue();
_cached = true; _cached = true;
_lastCache = DateTime.Now; _lastCache = IoCManager.Resolve<IGameTiming>().CurTime;
} }
return Value; return Value;

View File

@@ -0,0 +1,13 @@
using Content.Shared.GameObjects.Components.Inventory;
namespace Content.Server.AI.WorldState.States.Clothing
{
public sealed class ClothingSlotConState : PlanningStateData<EquipmentSlotDefines.Slots>
{
public override string Name => "ClothingSlotCon";
public override void Reset()
{
Value = EquipmentSlotDefines.Slots.NONE;
}
}
}

View File

@@ -0,0 +1,13 @@
using Content.Shared.GameObjects.Components.Inventory;
namespace Content.Server.AI.WorldState.States.Clothing
{
public sealed class ClothingSlotFlagConState : PlanningStateData<EquipmentSlotDefines.SlotFlags>
{
public override string Name => "ClothingSlotFlagCon";
public override void Reset()
{
Value = EquipmentSlotDefines.SlotFlags.NONE;
}
}
}

View File

@@ -6,25 +6,19 @@ using Robust.Shared.Interfaces.GameObjects;
namespace Content.Server.AI.WorldState.States.Inventory namespace Content.Server.AI.WorldState.States.Inventory
{ {
[UsedImplicitly] [UsedImplicitly]
public sealed class InventoryState : StateData<List<IEntity>> public sealed class EnumerableInventoryState : StateData<IEnumerable<IEntity>>
{ {
public override string Name => "Inventory"; public override string Name => "EnumerableInventory";
public override List<IEntity> GetValue() public override IEnumerable<IEntity> GetValue()
{ {
var inventory = new List<IEntity>();
if (Owner.TryGetComponent(out HandsComponent handsComponent)) if (Owner.TryGetComponent(out HandsComponent handsComponent))
{ {
foreach (var item in handsComponent.GetAllHeldItems()) foreach (var item in handsComponent.GetAllHeldItems())
{ {
inventory.Add(item.Owner); yield return item.Owner;
} }
} }
// TODO: InventoryComponent (Pockets were throwing)
return inventory;
} }
} }
} }

View File

@@ -0,0 +1,10 @@
namespace Content.Server.AI.WorldState.States.Utility
{
/// <summary>
/// Used by the utility AI to calc the adjusted scores
/// </summary>
public class ConsiderationState : StoredStateData<int>
{
public override string Name => "Consideration";
}
}

View File

@@ -0,0 +1,13 @@
using System;
namespace Content.Server.AI.WorldState.States.Utility
{
public sealed class StoredStateIsNullState : PlanningStateData<Type>
{
public override string Name => "StoredStateIsNull";
public override void Reset()
{
Value = null;
}
}
}

View File

@@ -4,6 +4,7 @@ using Content.Server.Interfaces.Chat;
using Content.Server.Interfaces.GameObjects; using Content.Server.Interfaces.GameObjects;
using Content.Server.Players; using Content.Server.Players;
using Content.Shared.GameObjects; using Content.Shared.GameObjects;
using Robust.Server.Console;
using Robust.Server.Interfaces.Console; using Robust.Server.Interfaces.Console;
using Robust.Server.Interfaces.Player; using Robust.Server.Interfaces.Player;
using Robust.Shared.Enums; using Robust.Shared.Enums;
@@ -80,6 +81,19 @@ namespace Content.Server.Chat
} }
} }
internal class AdminChatCommand : IClientCommand
{
public string Command => "asay";
public string Description => "Send chat messages to the private admin chat channel.";
public string Help => "asay <text>";
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
{
var chat = IoCManager.Resolve<IChatManager>();
chat.SendAdminChat(player, string.Join(" ", args));
}
}
internal class SuicideCommand : IClientCommand internal class SuicideCommand : IClientCommand
{ {
public string Command => "suicide"; public string Command => "suicide";

View File

@@ -7,6 +7,7 @@ using Content.Server.Observer;
using Content.Server.Players; using Content.Server.Players;
using Content.Shared.Chat; using Content.Shared.Chat;
using Content.Shared.GameObjects.EntitySystems; using Content.Shared.GameObjects.EntitySystems;
using Robust.Server.Console;
using Robust.Server.Interfaces.Player; using Robust.Server.Interfaces.Player;
using Robust.Shared.Interfaces.GameObjects; using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Network; using Robust.Shared.Interfaces.Network;
@@ -28,6 +29,7 @@ namespace Content.Server.Chat
[Dependency] private readonly IPlayerManager _playerManager; [Dependency] private readonly IPlayerManager _playerManager;
[Dependency] private readonly ILocalizationManager _localizationManager; [Dependency] private readonly ILocalizationManager _localizationManager;
[Dependency] private readonly IMoMMILink _mommiLink; [Dependency] private readonly IMoMMILink _mommiLink;
[Dependency] private readonly IConGroupController _conGroupController;
#pragma warning restore 649 #pragma warning restore 649
public void Initialize() public void Initialize()
@@ -112,6 +114,23 @@ namespace Content.Server.Chat
_netManager.ServerSendToMany(msg, clients.ToList()); _netManager.ServerSendToMany(msg, clients.ToList());
} }
public void SendAdminChat(IPlayerSession player, string message)
{
if(!_conGroupController.CanCommand(player, "asay"))
{
SendOOC(player, message);
return;
}
var clients = _playerManager.GetPlayersBy(x => _conGroupController.CanCommand(x, "asay")).Select(p => p.ConnectedClient);;
var msg = _netManager.CreateNetMessage<MsgChatMessage>();
msg.Channel = ChatChannel.AdminChat;
msg.Message = message;
msg.MessageWrap = $"{_localizationManager.GetString("ADMIN")}: {player.SessionId}: {{0}}";
_netManager.ServerSendToMany(msg, clients.ToList());
}
public void SendHookOOC(string sender, string message) public void SendHookOOC(string sender, string message)
{ {
var msg = _netManager.CreateNetMessage<MsgChatMessage>(); var msg = _netManager.CreateNetMessage<MsgChatMessage>();

View File

@@ -1,4 +1,5 @@
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups; using Content.Server.AI.Utility.Considerations;
using Content.Server.GameObjects.Components.NodeContainer.NodeGroups;
using Content.Server.GameObjects.Components.NodeContainer.Nodes; using Content.Server.GameObjects.Components.NodeContainer.Nodes;
using Content.Server.Interfaces; using Content.Server.Interfaces;
using Content.Server.AI.WorldState; using Content.Server.AI.WorldState;
@@ -72,6 +73,7 @@ namespace Content.Server
_gameTicker.Initialize(); _gameTicker.Initialize();
IoCManager.Resolve<RecipeManager>().Initialize(); IoCManager.Resolve<RecipeManager>().Initialize();
IoCManager.Resolve<BlackboardManager>().Initialize(); IoCManager.Resolve<BlackboardManager>().Initialize();
IoCManager.Resolve<ConsiderationsManager>().Initialize();
IoCManager.Resolve<IPDAUplinkManager>().Initialize(); IoCManager.Resolve<IPDAUplinkManager>().Initialize();
} }

View File

@@ -1,11 +1,10 @@
#nullable enable
using System.Collections.Generic; using System.Collections.Generic;
using Content.Server.Interfaces; using Content.Server.Interfaces;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
#nullable enable
namespace Content.Server.GameObjects.Components.Access namespace Content.Server.GameObjects.Components.Access
{ {
/// <summary> /// <summary>

View File

@@ -1,3 +1,4 @@
#nullable enable
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -11,8 +12,6 @@ using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
#nullable enable
namespace Content.Server.GameObjects.Components.Access namespace Content.Server.GameObjects.Components.Access
{ {
/// <summary> /// <summary>
@@ -69,7 +68,6 @@ namespace Content.Server.GameObjects.Components.Access
return _accessLists.Count == 0 || _accessLists.Any(a => a.IsSubsetOf(accessTags)); return _accessLists.Count == 0 || _accessLists.Any(a => a.IsSubsetOf(accessTags));
} }
[CanBeNull]
public static ICollection<string> FindAccessTags(IEntity entity) public static ICollection<string> FindAccessTags(IEntity entity)
{ {
if (entity.TryGetComponent(out IAccess accessComponent)) if (entity.TryGetComponent(out IAccess accessComponent))

View File

@@ -1,3 +1,4 @@
#nullable enable
using Content.Shared.Jobs; using Content.Shared.Jobs;
using Robust.Server.Interfaces.GameObjects; using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
@@ -5,8 +6,6 @@ using Robust.Shared.IoC;
using Robust.Shared.Prototypes; using Robust.Shared.Prototypes;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
#nullable enable
namespace Content.Server.GameObjects.Components.Access namespace Content.Server.GameObjects.Components.Access
{ {
[RegisterComponent] [RegisterComponent]

View File

@@ -1,10 +1,10 @@
using Content.Server.Cargo; #nullable enable
using Content.Server.Cargo;
using Content.Server.GameObjects.Components.Power.ApcNetComponents; using Content.Server.GameObjects.Components.Power.ApcNetComponents;
using Content.Server.GameObjects.EntitySystems; using Content.Server.GameObjects.EntitySystems;
using Content.Server.Interfaces.GameObjects.Components.Interaction; using Content.Server.Interfaces.GameObjects.Components.Interaction;
using Content.Shared.GameObjects.Components.Cargo; using Content.Shared.GameObjects.Components.Cargo;
using Content.Shared.Prototypes.Cargo; using Content.Shared.Prototypes.Cargo;
using JetBrains.Annotations;
using Robust.Server.GameObjects.Components.UserInterface; using Robust.Server.GameObjects.Components.UserInterface;
using Robust.Server.Interfaces.GameObjects; using Robust.Server.Interfaces.GameObjects;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
@@ -20,39 +20,43 @@ namespace Content.Server.GameObjects.Components.Cargo
public class CargoConsoleComponent : SharedCargoConsoleComponent, IActivate public class CargoConsoleComponent : SharedCargoConsoleComponent, IActivate
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly ICargoOrderDataManager _cargoOrderDataManager; [Dependency] private readonly ICargoOrderDataManager _cargoOrderDataManager = default!;
#pragma warning restore 649 #pragma warning restore 649
[ViewVariables] [ViewVariables]
public int Points = 1000; public int Points = 1000;
private BoundUserInterface _userInterface; private BoundUserInterface _userInterface = default!;
[ViewVariables] [ViewVariables]
public GalacticMarketComponent Market { get; private set; } public GalacticMarketComponent Market { get; private set; } = default!;
[ViewVariables]
public CargoOrderDatabaseComponent Orders { get; private set; }
private CargoBankAccount _bankAccount;
[ViewVariables] [ViewVariables]
[CanBeNull] public CargoOrderDatabaseComponent Orders { get; private set; } = default!;
public CargoBankAccount BankAccount
private CargoBankAccount? _bankAccount;
[ViewVariables]
public CargoBankAccount? BankAccount
{ {
get => _bankAccount; get => _bankAccount;
private set private set
{ {
if (_bankAccount == value) if (_bankAccount == value)
{
return; return;
}
if (_bankAccount != null) if (_bankAccount != null)
{ {
_bankAccount.OnBalanceChange -= UpdateUIState; _bankAccount.OnBalanceChange -= UpdateUIState;
} }
_bankAccount = value; _bankAccount = value;
if (value != null) if (value != null)
{ {
_bankAccount.OnBalanceChange += UpdateUIState; value.OnBalanceChange += UpdateUIState;
} }
UpdateUIState(); UpdateUIState();
@@ -61,9 +65,9 @@ namespace Content.Server.GameObjects.Components.Cargo
private bool _requestOnly = false; private bool _requestOnly = false;
private PowerReceiverComponent _powerReceiver; private PowerReceiverComponent _powerReceiver = default!;
private bool Powered => _powerReceiver.Powered; private bool Powered => _powerReceiver.Powered;
private CargoConsoleSystem _cargoConsoleSystem; private CargoConsoleSystem _cargoConsoleSystem = default!;
public override void Initialize() public override void Initialize()
{ {
@@ -98,8 +102,11 @@ namespace Content.Server.GameObjects.Components.Cargo
{ {
case CargoConsoleAddOrderMessage msg: case CargoConsoleAddOrderMessage msg:
{ {
if (msg.Amount <= 0) if (msg.Amount <= 0 || _bankAccount == null)
{
break; break;
}
_cargoOrderDataManager.AddOrder(Orders.Database.Id, msg.Requester, msg.Reason, msg.ProductId, msg.Amount, _bankAccount.Id); _cargoOrderDataManager.AddOrder(Orders.Database.Id, msg.Requester, msg.Reason, msg.ProductId, msg.Amount, _bankAccount.Id);
break; break;
} }
@@ -111,8 +118,12 @@ namespace Content.Server.GameObjects.Components.Cargo
case CargoConsoleApproveOrderMessage msg: case CargoConsoleApproveOrderMessage msg:
{ {
if (_requestOnly || if (_requestOnly ||
!Orders.Database.TryGetOrder(msg.OrderNumber, out var order)) !Orders.Database.TryGetOrder(msg.OrderNumber, out var order) ||
_bankAccount == null)
{
break; break;
}
_prototypeManager.TryIndex(order.ProductId, out CargoProductPrototype product); _prototypeManager.TryIndex(order.ProductId, out CargoProductPrototype product);
if (product == null) if (product == null)
break; break;

View File

@@ -224,6 +224,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
if (!ActionBlockerSystem.CanInteract(user) || if (!ActionBlockerSystem.CanInteract(user) ||
!user.TryGetComponent<HandsComponent>(out var hands) || !user.TryGetComponent<HandsComponent>(out var hands) ||
hands.GetActiveHand == null || hands.GetActiveHand == null ||
hands.GetActiveHand.Owner == component.Owner ||
!hands.GetActiveHand.Owner.TryGetComponent<SolutionComponent>(out var solution)) !hands.GetActiveHand.Owner.TryGetComponent<SolutionComponent>(out var solution))
{ {
data.Visibility = VerbVisibility.Invisible; data.Visibility = VerbVisibility.Invisible;
@@ -323,6 +324,7 @@ namespace Content.Server.GameObjects.Components.Chemistry
if (!ActionBlockerSystem.CanInteract(user) || if (!ActionBlockerSystem.CanInteract(user) ||
!user.TryGetComponent<HandsComponent>(out var hands) || !user.TryGetComponent<HandsComponent>(out var hands) ||
hands.GetActiveHand == null || hands.GetActiveHand == null ||
hands.GetActiveHand.Owner == component.Owner ||
!hands.GetActiveHand.Owner.TryGetComponent<SolutionComponent>(out var solution)) !hands.GetActiveHand.Owner.TryGetComponent<SolutionComponent>(out var solution))
{ {
data.Visibility = VerbVisibility.Invisible; data.Visibility = VerbVisibility.Invisible;

View File

@@ -21,7 +21,7 @@ namespace Content.Server.GameObjects.Components.Explosion
public override string Name => "FlashExplosive"; public override string Name => "FlashExplosive";
private float _range; private float _range;
private double _duration; private float _duration;
private string _sound; private string _sound;
private bool _deleteOnFlash; private bool _deleteOnFlash;
@@ -30,7 +30,7 @@ namespace Content.Server.GameObjects.Components.Explosion
base.ExposeData(serializer); base.ExposeData(serializer);
serializer.DataField(ref _range, "range", 7.0f); serializer.DataField(ref _range, "range", 7.0f);
serializer.DataField(ref _duration, "duration", 8.0); serializer.DataField(ref _duration, "duration", 8.0f);
serializer.DataField(ref _sound, "sound", "/Audio/Effects/flash_bang.ogg"); serializer.DataField(ref _sound, "sound", "/Audio/Effects/flash_bang.ogg");
serializer.DataField(ref _deleteOnFlash, "deleteOnFlash", true); serializer.DataField(ref _deleteOnFlash, "deleteOnFlash", true);
} }
@@ -41,7 +41,7 @@ namespace Content.Server.GameObjects.Components.Explosion
ContainerHelpers.TryGetContainer(Owner, out var container); ContainerHelpers.TryGetContainer(Owner, out var container);
if (container == null || !container.Owner.HasComponent<EntityStorageComponent>()) if (container == null || !container.Owner.HasComponent<EntityStorageComponent>())
{ {
ServerFlashableComponent.FlashAreaHelper(Owner, _range, _duration); FlashableComponent.FlashAreaHelper(Owner, _range, _duration);
} }
if (_sound != null) if (_sound != null)

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Runtime.Remoting; using System.Runtime.Remoting;
using Content.Server.GameObjects.Components.Chemistry; using Content.Server.GameObjects.Components.Chemistry;
using Content.Server.GameObjects.Components.Items.Storage; using Content.Server.GameObjects.Components.Items.Storage;
@@ -25,11 +26,11 @@ namespace Content.Server.GameObjects.Components.Interactable
[RegisterComponent] [RegisterComponent]
[ComponentReference(typeof(ToolComponent))] [ComponentReference(typeof(ToolComponent))]
[ComponentReference(typeof(IToolComponent))] [ComponentReference(typeof(IToolComponent))]
public class WelderComponent : ToolComponent, IExamine, IUse, ISuicideAct public class WelderComponent : ToolComponent, IExamine, IUse, ISuicideAct, ISolutionChange
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private IEntitySystemManager _entitySystemManager; [Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
[Dependency] private IServerNotifyManager _notifyManager; [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
#pragma warning restore 649 #pragma warning restore 649
public override string Name => "Welder"; public override string Name => "Welder";
@@ -45,10 +46,11 @@ namespace Content.Server.GameObjects.Components.Interactable
/// </summary> /// </summary>
public const float FuelLossRate = 0.5f; public const float FuelLossRate = 0.5f;
private bool _welderLit = false; private bool _welderLit;
private WelderSystem _welderSystem; private WelderSystem _welderSystem = default!;
private SpriteComponent _spriteComponent; private SpriteComponent? _spriteComponent;
private SolutionComponent _solutionComponent; private SolutionComponent? _solutionComponent;
private PointLightComponent? _pointLightComponent;
[ViewVariables] [ViewVariables]
public float Fuel => _solutionComponent?.Solution.GetReagentQuantity("chem.WeldingFuel").Float() ?? 0f; public float Fuel => _solutionComponent?.Solution.GetReagentQuantity("chem.WeldingFuel").Float() ?? 0f;
@@ -80,6 +82,7 @@ namespace Content.Server.GameObjects.Components.Interactable
Owner.TryGetComponent(out _solutionComponent); Owner.TryGetComponent(out _solutionComponent);
Owner.TryGetComponent(out _spriteComponent); Owner.TryGetComponent(out _spriteComponent);
Owner.TryGetComponent(out _pointLightComponent);
} }
public override ComponentState GetComponentState() public override ComponentState GetComponentState()
@@ -99,7 +102,7 @@ namespace Content.Server.GameObjects.Components.Interactable
return base.UseTool(user, target, toolQualityNeeded) && TryWeld(fuelConsumed, user); return base.UseTool(user, target, toolQualityNeeded) && TryWeld(fuelConsumed, user);
} }
private bool TryWeld(float value, IEntity user = null, bool silent = false) private bool TryWeld(float value, IEntity? user = null, bool silent = false)
{ {
if (!WelderLit) if (!WelderLit)
{ {
@@ -132,7 +135,7 @@ namespace Content.Server.GameObjects.Components.Interactable
/// <summary> /// <summary>
/// Deactivates welding tool if active, activates welding tool if possible /// Deactivates welding tool if active, activates welding tool if possible
/// </summary> /// </summary>
private bool ToggleWelderStatus(IEntity user = null) private bool ToggleWelderStatus(IEntity? user = null)
{ {
var item = Owner.GetComponent<ItemComponent>(); var item = Owner.GetComponent<ItemComponent>();
@@ -141,7 +144,10 @@ namespace Content.Server.GameObjects.Components.Interactable
WelderLit = false; WelderLit = false;
// Layer 1 is the flame. // Layer 1 is the flame.
item.EquippedPrefix = "off"; item.EquippedPrefix = "off";
_spriteComponent.LayerSetVisible(1, false); _spriteComponent?.LayerSetVisible(1, false);
if (_pointLightComponent != null) _pointLightComponent.Enabled = false;
PlaySoundCollection("WelderOff", -5); PlaySoundCollection("WelderOff", -5);
_welderSystem.Unsubscribe(this); _welderSystem.Unsubscribe(this);
return true; return true;
@@ -155,7 +161,10 @@ namespace Content.Server.GameObjects.Components.Interactable
WelderLit = true; WelderLit = true;
item.EquippedPrefix = "on"; item.EquippedPrefix = "on";
_spriteComponent.LayerSetVisible(1, true); _spriteComponent?.LayerSetVisible(1, true);
if (_pointLightComponent != null) _pointLightComponent.Enabled = true;
PlaySoundCollection("WelderOn", -5); PlaySoundCollection("WelderOn", -5);
_welderSystem.Subscribe(this); _welderSystem.Subscribe(this);
return true; return true;
@@ -189,12 +198,11 @@ namespace Content.Server.GameObjects.Components.Interactable
if (!HasQuality(ToolQuality.Welding) || !WelderLit) if (!HasQuality(ToolQuality.Welding) || !WelderLit)
return; return;
_solutionComponent.TryRemoveReagent("chem.WeldingFuel", ReagentUnit.New(FuelLossRate * frameTime)); _solutionComponent?.TryRemoveReagent("chem.WeldingFuel", ReagentUnit.New(FuelLossRate * frameTime));
if (Fuel == 0) if (Fuel == 0)
ToggleWelderStatus(); ToggleWelderStatus();
Dirty();
} }
public SuicideKind Suicide(IEntity victim, IChatManager chat) public SuicideKind Suicide(IEntity victim, IChatManager chat)
@@ -208,5 +216,10 @@ namespace Content.Server.GameObjects.Components.Interactable
chat.EntityMe(victim, Loc.GetString("bashes {0:themselves} with the {1}!", victim, Owner.Name)); chat.EntityMe(victim, Loc.GetString("bashes {0:themselves} with the {1}!", victim, Owner.Name));
return SuicideKind.Brute; return SuicideKind.Brute;
} }
public void SolutionChanged(SolutionChangeEventArgs eventArgs)
{
Dirty();
}
} }
} }

View File

@@ -1,11 +1,7 @@
using Content.Shared.GameObjects.Components.Movement; #nullable enable
using Content.Shared.GameObjects.Components.Movement;
using Robust.Shared.GameObjects; using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects.Components;
using Robust.Shared.Map; using Robust.Shared.Map;
using Robust.Shared.Physics;
using Robust.Shared.ViewVariables;
#nullable enable
namespace Content.Server.GameObjects.Components.Movement namespace Content.Server.GameObjects.Components.Movement
{ {

View File

@@ -1,3 +1,4 @@
#nullable enable
using System; using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
@@ -23,8 +24,6 @@ using Robust.Shared.Localization;
using Robust.Shared.Serialization; using Robust.Shared.Serialization;
using Robust.Shared.ViewVariables; using Robust.Shared.ViewVariables;
#nullable enable
namespace Content.Server.GameObjects.Components.PDA namespace Content.Server.GameObjects.Components.PDA
{ {
[RegisterComponent] [RegisterComponent]

View File

@@ -17,16 +17,16 @@ namespace Content.Server.GameObjects.Components.Projectiles
{ {
public override string Name => "FlashProjectile"; public override string Name => "FlashProjectile";
private double _range; private float _range;
private double _duration; private float _duration;
private bool _flashed; private bool _flashed;
public override void ExposeData(ObjectSerializer serializer) public override void ExposeData(ObjectSerializer serializer)
{ {
base.ExposeData(serializer); base.ExposeData(serializer);
serializer.DataField(ref _range, "range", 1.0); serializer.DataField(ref _range, "range", 1.0f);
serializer.DataField(ref _duration, "duration", 8.0); serializer.DataField(ref _duration, "duration", 8.0f);
} }
public override void Initialize() public override void Initialize()
@@ -45,7 +45,7 @@ namespace Content.Server.GameObjects.Components.Projectiles
{ {
return; return;
} }
ServerFlashableComponent.FlashAreaHelper(Owner, _range, _duration); FlashableComponent.FlashAreaHelper(Owner, _range, _duration);
_flashed = true; _flashed = true;
} }

View File

@@ -0,0 +1,53 @@
using System;
using System.Linq;
using Content.Server.Utility;
using Content.Shared.GameObjects.Components.Weapons;
using Content.Shared.GameObjects.EntitySystems;
using Content.Shared.Physics;
using Robust.Server.GameObjects.EntitySystems;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Physics;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
namespace Content.Server.GameObjects.Components.Weapon
{
[RegisterComponent]
public sealed class FlashableComponent : SharedFlashableComponent
{
private double _duration;
private TimeSpan _lastFlash;
public void Flash(double duration)
{
var timing = IoCManager.Resolve<IGameTiming>();
_lastFlash = timing.CurTime;
_duration = duration;
Dirty();
}
public override ComponentState GetComponentState()
{
return new FlashComponentState(_duration, _lastFlash);
}
public static void FlashAreaHelper(IEntity source, float range, float duration, string sound = null)
{
foreach (var entity in IoCManager.Resolve<IEntityManager>().GetEntitiesInRange(source.Transform.GridPosition, range))
{
if (!InteractionChecks.InRangeUnobstructed(source, entity.Transform.MapPosition, range, ignoredEnt:entity))
continue;
if(entity.TryGetComponent(out FlashableComponent flashable))
flashable.Flash(duration);
}
if (!string.IsNullOrEmpty(sound))
{
IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>().PlayAtCoords(sound, source.Transform.GridPosition);
}
}
}
}

View File

@@ -53,7 +53,7 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
private float _slowdownTime = 5f; private float _slowdownTime = 5f;
[ViewVariables(VVAccess.ReadWrite)] public float EnergyPerUse { get; set; } = 1000; [ViewVariables(VVAccess.ReadWrite)] public float EnergyPerUse { get; set; } = 50;
[ViewVariables] [ViewVariables]
public bool Activated => _activated; public bool Activated => _activated;
@@ -89,13 +89,12 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
protected override bool OnHitEntities(IReadOnlyList<IEntity> entities, AttackEventArgs eventArgs) protected override bool OnHitEntities(IReadOnlyList<IEntity> entities, AttackEventArgs eventArgs)
{ {
var cell = Cell; if (!Activated || entities.Count == 0 || Cell == null)
if (!Activated || entities.Count == 0 || cell == null) return true;
return false;
if (!cell.TryUseCharge(EnergyPerUse)) if (!Cell.TryUseCharge(EnergyPerUse))
{ return true;
return false;
}
EntitySystem.Get<AudioSystem>().PlayAtCoords("/Audio/Weapons/egloves.ogg", Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f)); EntitySystem.Get<AudioSystem>().PlayAtCoords("/Audio/Weapons/egloves.ogg", Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
foreach (var entity in entities) foreach (var entity in entities)
@@ -113,11 +112,11 @@ namespace Content.Server.GameObjects.Components.Weapon.Melee
else else
stunnable.Slowdown(_slowdownTime); stunnable.Slowdown(_slowdownTime);
} }
if(cell.CurrentCharge < EnergyPerUse)
{ if (!(Cell.CurrentCharge < EnergyPerUse)) return true;
EntitySystem.Get<AudioSystem>().PlayAtCoords(AudioHelpers.GetRandomFileFromSoundCollection("sparks"), Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
TurnOff(); EntitySystem.Get<AudioSystem>().PlayAtCoords(AudioHelpers.GetRandomFileFromSoundCollection("sparks"), Owner.Transform.GridPosition, AudioHelpers.WithVariation(0.25f));
} TurnOff();
return true; return true;
} }

View File

@@ -1,78 +0,0 @@
using System;
using System.Linq;
using Content.Shared.GameObjects.Components.Weapons;
using Content.Shared.Physics;
using Robust.Server.GameObjects.EntitySystems;
using Robust.Shared.GameObjects;
using Robust.Shared.Interfaces.GameObjects;
using Robust.Shared.Interfaces.Physics;
using Robust.Shared.Interfaces.Timing;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
namespace Content.Server.GameObjects.Components.Weapon
{
[RegisterComponent]
public sealed class ServerFlashableComponent : SharedFlashableComponent
{
private double _duration;
private TimeSpan _lastFlash;
public void Flash(double duration)
{
var timing = IoCManager.Resolve<IGameTiming>();
_lastFlash = timing.CurTime;
_duration = duration;
Dirty();
}
public override ComponentState GetComponentState()
{
return new FlashComponentState(_duration, _lastFlash);
}
public static void FlashAreaHelper(IEntity source, double range, double duration, string sound = null)
{
var physicsManager = IoCManager.Resolve<IPhysicsManager>();
var entityManager = IoCManager.Resolve<IEntityManager>();
foreach (var entity in entityManager.GetEntities(new TypeEntityQuery(typeof(ServerFlashableComponent))))
{
if (source.Transform.MapID != entity.Transform.MapID ||
entity == source)
{
continue;
}
var direction = entity.Transform.WorldPosition - source.Transform.WorldPosition;
if (direction.Length > range)
{
continue;
}
// Direction will be zero if they're hit with the source only I think
if (direction == Vector2.Zero)
{
continue;
}
var ray = new CollisionRay(source.Transform.WorldPosition, direction.Normalized, (int) CollisionGroup.Opaque);
var rayCastResults = physicsManager.IntersectRay(source.Transform.MapID, ray, direction.Length, source, false).ToList();
if (rayCastResults.Count == 0 ||
rayCastResults[0].HitEntity != entity)
{
continue;
}
var flashable = entity.GetComponent<ServerFlashableComponent>();
flashable.Flash(duration);
}
if (sound != null)
{
IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<AudioSystem>().PlayAtCoords(sound, source.Transform.GridPosition);
}
}
}
}

View File

@@ -1,4 +1,5 @@
using System; #nullable enable
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using Content.Server.GameObjects.Components.Interactable; using Content.Server.GameObjects.Components.Interactable;
@@ -32,12 +33,12 @@ namespace Content.Server.GameObjects.Components
public class WiresComponent : SharedWiresComponent, IInteractUsing, IExamine, IMapInit public class WiresComponent : SharedWiresComponent, IInteractUsing, IExamine, IMapInit
{ {
#pragma warning disable 649 #pragma warning disable 649
[Dependency] private readonly IRobustRandom _random; [Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IServerNotifyManager _notifyManager; [Dependency] private readonly IServerNotifyManager _notifyManager = default!;
#pragma warning restore 649 #pragma warning restore 649
private AudioSystem _audioSystem; private AudioSystem _audioSystem = default!;
private AppearanceComponent _appearance; private AppearanceComponent _appearance = default!;
private BoundUserInterface _userInterface; private BoundUserInterface _userInterface = default!;
private bool _isPanelOpen; private bool _isPanelOpen;
@@ -93,7 +94,7 @@ namespace Content.Server.GameObjects.Components
} }
[ViewVariables(VVAccess.ReadWrite)] [ViewVariables(VVAccess.ReadWrite)]
public string SerialNumber public string? SerialNumber
{ {
get => _serialNumber; get => _serialNumber;
set set
@@ -127,16 +128,16 @@ namespace Content.Server.GameObjects.Components
private readonly List<WireLetter> _availableLetters = private readonly List<WireLetter> _availableLetters =
new List<WireLetter>((WireLetter[]) Enum.GetValues(typeof(WireLetter))); new List<WireLetter>((WireLetter[]) Enum.GetValues(typeof(WireLetter)));
private string _boardName; private string _boardName = default!;
private string _serialNumber; private string? _serialNumber;
// Used to generate wire appearance randomization client side. // Used to generate wire appearance randomization client side.
// We honestly don't care what it is or such but do care that it doesn't change between UI re-opens. // We honestly don't care what it is or such but do care that it doesn't change between UI re-opens.
[ViewVariables] [ViewVariables]
private int _wireSeed; private int _wireSeed;
[ViewVariables] [ViewVariables]
private string _layoutId; private string? _layoutId;
public override void Initialize() public override void Initialize()
{ {
@@ -186,7 +187,7 @@ namespace Content.Server.GameObjects.Components
base.Startup(); base.Startup();
WireLayout layout = null; WireLayout? layout = null;
var hackingSystem = EntitySystem.Get<WireHackingSystem>(); var hackingSystem = EntitySystem.Get<WireHackingSystem>();
if (_layoutId != null) if (_layoutId != null)
{ {
@@ -299,9 +300,9 @@ namespace Content.Server.GameObjects.Components
{ {
[NotNull] private readonly WiresComponent _wires; [NotNull] private readonly WiresComponent _wires;
[NotNull] private readonly IWires _owner; [NotNull] private readonly IWires _owner;
[CanBeNull] private readonly WireLayout _layout; private readonly WireLayout? _layout;
public WiresBuilder(WiresComponent wires, IWires owner, WireLayout layout) public WiresBuilder(WiresComponent wires, IWires owner, WireLayout? layout)
{ {
_wires = wires; _wires = wires;
_owner = owner; _owner = owner;
@@ -365,12 +366,12 @@ namespace Content.Server.GameObjects.Components
{ {
case WiresActionMessage msg: case WiresActionMessage msg:
var wire = WiresList.Find(x => x.Id == msg.Id); var wire = WiresList.Find(x => x.Id == msg.Id);
if (wire == null) var player = serverMsg.Session.AttachedEntity;
if (wire == null || player == null)
{ {
return; return;
} }
var player = serverMsg.Session.AttachedEntity;
if (!player.TryGetComponent(out IHandsComponent handsComponent)) if (!player.TryGetComponent(out IHandsComponent handsComponent))
{ {
_notifyManager.PopupMessage(Owner.Transform.GridPosition, player, _notifyManager.PopupMessage(Owner.Transform.GridPosition, player,
@@ -386,7 +387,7 @@ namespace Content.Server.GameObjects.Components
} }
var activeHandEntity = handsComponent.GetActiveHand?.Owner; var activeHandEntity = handsComponent.GetActiveHand?.Owner;
ToolComponent tool = null; ToolComponent? tool = null;
activeHandEntity?.TryGetComponent(out tool); activeHandEntity?.TryGetComponent(out tool);
switch (msg.Action) switch (msg.Action)

View File

@@ -0,0 +1,70 @@
using System.Collections.Generic;
using Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Pathfinders;
using Content.Server.GameObjects.EntitySystems.Pathfinding;
using Robust.Shared.GameObjects.Systems;
using Robust.Shared.Map;
namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding.Accessible
{
/// <summary>
/// The simplest pathfinder
/// </summary>
public sealed class BFSPathfinder
{
/// <summary>
/// Gets all of the tiles in range that can we access
/// </summary>
/// If you want Dikstra then add distances.
/// Doesn't use the JobQueue as it will generally be encapsulated by other jobs
/// <param name="pathfindingArgs"></param>
/// <param name="range"></param>
/// <param name="fromStart">Whether we traverse from the starting tile or the end tile</param>
/// <returns></returns>
public static IEnumerable<PathfindingNode> GetNodesInRange(PathfindingArgs pathfindingArgs, bool fromStart = true)
{
var pathfindingSystem = EntitySystem.Get<PathfindingSystem>();
// Don't need a priority queue given not looking for shortest path
var openTiles = new Queue<PathfindingNode>();
var closedTiles = new HashSet<TileRef>();
PathfindingNode startNode;
if (fromStart)
{
startNode = pathfindingSystem.GetNode(pathfindingArgs.Start);
}
else
{
startNode = pathfindingSystem.GetNode(pathfindingArgs.End);
}
PathfindingNode currentNode;
openTiles.Enqueue(startNode);
while (openTiles.Count > 0)
{
currentNode = openTiles.Dequeue();
foreach (var neighbor in currentNode.GetNeighbors())
{
// No distances stored so can just check closed tiles here
if (closedTiles.Contains(neighbor.TileRef)) continue;
closedTiles.Add(currentNode.TileRef);
// So currently tileCost gets the octile distance between the 2 so we'll also use that for our range check
var tileCost = PathfindingHelpers.GetTileCost(pathfindingArgs, startNode, neighbor);
var direction = PathfindingHelpers.RelativeDirection(neighbor, currentNode);
if (tileCost == null ||
tileCost > pathfindingArgs.Proximity ||
!PathfindingHelpers.DirectionTraversable(pathfindingArgs.CollisionMask, pathfindingArgs.Access, currentNode, direction))
{
continue;
}
openTiles.Enqueue(neighbor);
yield return neighbor;
}
}
}
}
}

View File

@@ -29,9 +29,8 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding
_indices = indices; _indices = indices;
} }
public void Initialize() public void Initialize(IMapGrid grid)
{ {
var grid = IoCManager.Resolve<IMapManager>().GetGrid(GridId);
for (var x = 0; x < ChunkSize; x++) for (var x = 0; x < ChunkSize; x++)
{ {
for (var y = 0; y < ChunkSize; y++) for (var y = 0; y < ChunkSize; y++)
@@ -157,12 +156,6 @@ namespace Content.Server.GameObjects.EntitySystems.AI.Pathfinding
return _nodes[chunkX, chunkY]; return _nodes[chunkX, chunkY];
} }
public void UpdateNode(TileRef tile)
{
var node = GetNode(tile);
node.UpdateTile(tile);
}
private void CreateNode(TileRef tile, PathfindingChunk parent = null) private void CreateNode(TileRef tile, PathfindingChunk parent = null)
{ {
if (parent == null) if (parent == null)

Some files were not shown because too many files have changed in this diff Show More