mirror of
https://github.com/DeltaV-Station/Delta-v.git
synced 2026-09-30 08:07:28 +00:00
* Fix the sensor monitoring console forcing a GC every 3 seconds (#38146) * Optimize sensor monitoring window graph drawing * Add shared static Vector2 pool for all GraphView instances * Address requested changes * remove lock * Update submodule to 264.0.0 (#38629) * Toy/Plushie Inhands and Wearables (#38514) * Fixed dependency injection and some other issues in a few places. * More issue fixes * patchfor broken NetworkConfiguratorLinkMenu (#38632) fix * Fix solutions flickering when transferring contents (#34838) * Use Solution clones when applying SolutionComponent states * Revert "Use Solution clones when applying SolutionComponent states" This reverts commit 013fd111cf92b22562e00f98a7aaa49bc4b4ed62. * Make Solution implement ICloneable and rename Clone method. * Copy CanReact value when cloning a Solution * Convert to IRobustCloneable * Fix typos in guidebook: Buisness → Business (#38636) * Fix typo in `MinorAntagonists.xml` Buisness → Business * Fix typo in `YourFirstCharacter.xml` Buisness → Business * Various Headphones Fixes and Tweaks (#38479) * sprites, wearables * neck * icon-on sprite * Cleanup prototype instantiation in `DamageTest` (#38639) Cleanup prototype instantiation in DamageTest * Cleanup prototype instantiation in `ExplosionSystem` (#38642) Cleanup prototype instantiation in ExplosionSystem * AddBodyPartCommand localization. (#38612) commit * fix ItemSlotsSystem debug assert (#38655) * Allow the Command & Super door remotes to use the access of their user. (Re-creation of PR due to changes to game balance) (#35536) * Added directional beacons (#38284) * Added directional beacons Signed-off-by: Nox38 <nebulousnox38@gmail.com> * Fixed names Signed-off-by: Nox38 <nebulousnox38@gmail.com> --------- Signed-off-by: Nox38 <nebulousnox38@gmail.com> * Power stat and nuke codes commands get some LEC love. (#38585) * commit * requested changes. * Dsay Dirty and Follow commands converted to LEC and localized. (#38666) * commit * whoopwhoopwhoop * Retro laser sprite fix (#38676) * Fixed everything except the icon Signed-off-by: Nox38 <nebulousnox38@gmail.com> * fixed icon Signed-off-by: Nox38 <nebulousnox38@gmail.com> --------- Signed-off-by: Nox38 <nebulousnox38@gmail.com> * fix water coolers (#38681) * Monochromacy typo fix (#38686) * fixes the typo * Fixed cloning looking for the trait, not the component, RE https://github.com/space-wizards/space-station-14/pull/38686#issuecomment-3025093504 * Apply suggestions from code review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Validate `CloningSettingsPrototype`s (#38688) * Validate CloningSettingsPrototypes * Update Content.IntegrationTests/Tests/Cloning/CloningSettingsPrototypeTest.cs Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Check EventComponents too --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Add test of objective-related console commands (#36400) * Add test of objective add/list/remove commands * Not sure why we're validating test prototypes, but sure * We don't need a map * Improvements and fixups for New Status Effect API (#38660) * Predict healing and bloodstream (#38690) * initial commit * reapply 38126 * fix rootable * someone missed an important minus sign here * try this * fix * fix * reenable crit hits * cleanup * fix status time dirtying * fix * camelCase * Healing and bloodstream prediction fixes. * Resolving Wizard casting recall on nuke disk making it impossible to disarm (#38661) * Resolving Wizard Recall on Nuke disk making it impossible to disarm - Adding a DisarmBomb case to nuke status update loop - Changing a few methods and parameters to properly follow formatting standards - Updating some names to follow camelCase * Updating missed tag * Reverting DataField change Should prevent this preventative bugfix being a breaking change. * Switch HSV to the default colorspace for character customization (#38434) * Made HSV default for character editor * Adds/fixes comments to HSV defaulting * Added dropbox fix, potentially cursed * Revert "Added dropbox fix, potentially cursed" This reverts commit a709883366fbee813e839742125e70844672af29. --------- Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com> * Fix: Don't deploy foldables when clicking on items inside containers (#38709) * Fix * Apply suggestions from code review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Pressure Relief Valve (#36708) * initial system (this math is probably WRONG) * General code cleanup and OnExamined support (holy moly this code sucks) * UICode and related events foundation TODO: - Actually write the XAML UI and the underlying system - Un-shitcode the entire thing - Actually test everything... * Working UI code TODO: Make predicted, as this certainly isn't predicted. Even though I said it was. It isn't. * Remove one TODO for unshitcoding the examine code * Add reminder yea * Make predicted (defenitely isn't) (also defenitely isn't a copypaste from pressure pump code) * It's predicted! TODO: - Give it snazzy predicted visuals! - Have a different field for pressure entry, lest it gets bulldozed every UI update. * Improve gas pressure relief valve UI TODO: Reminder to reduce amount of dirties using deltafields * Implement DirtyField prediction * Entity<T> cleanup A lot of Entity<T> conversions and lukewarm cleanup. Also got caught copy pasting code in 4K UHD but it's not like you couldn't tell. * More cleanup and comments * Remove TODO comment on bulldozing window title * """refactoring""" - Move appearance out of shared and finally fix it. Pointless to predict appearance in this instance. - More Entity<T> conversions because I like them. - Move UI creation handling over entirely to the ActivatableUI system. - Fix a hardcoded locale string (why????). * Add visuals * Revert debugging variable replacememt yea * Revert skissue * Remove unused using directives and remove TODO * Localize, cleanup, document * Fix adminlogging discrepancy * Add ability to construct, add guidebook entry * Clear up comment * Add guidebook tooltip to valve * Convert GasPressureReliefValveBoundUserInterface declaration into primary constructor * Adds more input handling and adds autofill on open * Un-deepfry input validator shitcode Genuinely what was I smoking * improve visuals logic * Refactor again - Update math to the correct implementation - Moved code that could be re-used in the future into a helper method under AtmosphereSystem.Gases.cs * I'm sorry but I hate warnings * Remove unused using directive in AtmosphereSystem.Gases.cs * Review and cleanup * Lukewarm UI glossup * Maintainer for the upstream project btw * Remove redundant state sets and messy logic * Unduplicate valve updater code * Redo UI (im sorry Slarti) * run tests * Test refactored UI messaging * Second round of UI improvements - God please find a way to improve this system. Feels bad. * Update loop implementation * Further predict UI * Clear up SetToCurrentThreshold * cleanup * Update to master + pipe layers and bug fixes want to run tests * fixes * Deploy rename pipebomb * Documentation and requested changes * Rename the method that wiggled away * Undo rounding changes * Fix comment * Rename and cleanup * Apply suggestions from code review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Fix TextLinkTag (#32203) * Adjust uplink buy button to be under item icon (#38596) * Adjusted uplink buy button to be under item icon * Put the discount subtext under the icon * Indent fixes, added margin --------- Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com> * Scurrets - Audio Improvements (#38482) * Scurret audio tuning * Add new sfx * Update sneezing sfx * YAML support * Rename a folder * make telesci wreck easier (#37569) rel * Validate `ShaderPrototype` IDs (#38728) * Convert all shader prototype string literals to protoids in overlays * Convert more shader prototype literal strings to protoids * Convert ValidatePrototypeId to ProtoId * Later * [BUGFIX] Fixed revenant malfunction ability not working properly only MediBots and Stasis bed (#38664) * fixed * clean up * orks fix smart * review fix 1 * more requested changes * less cursed * more descriptive description * better wording * Tiny Tiny Cleanup of the EyeClosingSystem. (#38734) Update EyeClosingSystem.cs * Fix human skin tone distribution (#38701) * fix: Use PredictedQueueDel for gib spell (#38729) * fix: don't default to uncharged sprite state for cells (#38730) * Fix Hristov description - remove inaccurate technical specs (#38746) - Removes inaccurate 'armor piercing 14.5mm shells' reference - Replaces it with a more funny description, matching the style of the other snipers and guns - Keeps ammunition type '.60 anti-materiel ammo' specification - Fixes issue #38590 Co-authored-by: Arthur Fiorese de Andrade <aandrade@cmcxs.gov.br> * feat: allow mopping evaporating puddles (#38743) * Validate remaining `ProtoId` strings (#38747) Validate remaining ProtoId strings * Validate `ProtoId`s in tests (#38745) * Convert string literals to protoids in Content.Tests * Convert string literals to protoids or consts in Content.IntegrationTests * Fix linter failures Tricksy static using misled me * Cleanup warning in StomachSystem (#38748) you did not see this * Vox scars (#38592) * Added vox scars n'stuff, renamed vox_tattoos.ftl to just vox.ftl * Revert "Added vox scars n'stuff, renamed vox_tattoos.ftl to just vox.ftl" This reverts commit c73da55ba3b39ddf93b493aecd85604c54dd8a15. * locale key fix * Changed top surgery scar names to be more generalized * Adjusted face scars * Formatting fixes --------- Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com> * UnlockNode command to LEC. (#38751) * commit * Update UnlockNodeCommand.cs * commit * move command locale to its own file. * Update Content.Server/Xenoarchaeology/Artifact/UnlockNodeCommand.cs --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Typofixes for figurine dialogue (#38737) * Typofixes for figurine dialogue * Forgot two * Janitor Tool: Wire Brush (#38667) * Wow! It's -brush- * spacing. * Update Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Update Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * fixed changes --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Minor escape menu UX improvements (#38650) * fix: spellbooks can have infinite charges (#38376) * fix: spellbooks can have infinite charges * refactor: indicate infinite spellbook charges with null Not sure if I like this much better...
473 lines
16 KiB
C#
473 lines
16 KiB
C#
using System.Linq;
|
|
using System.Numerics;
|
|
using System.Threading;
|
|
using Content.Client.Verbs;
|
|
using Content.Shared.Examine;
|
|
using Content.Shared.IdentityManagement;
|
|
using Content.Shared.Input;
|
|
using Content.Shared.Interaction.Events;
|
|
using Content.Shared.Item;
|
|
using Content.Shared.Verbs;
|
|
using JetBrains.Annotations;
|
|
using Robust.Client.GameObjects;
|
|
using Robust.Client.Graphics;
|
|
using Robust.Client.Player;
|
|
using Robust.Client.UserInterface;
|
|
using Robust.Client.UserInterface.Controls;
|
|
using Robust.Shared.Input.Binding;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Utility;
|
|
using static Content.Shared.Interaction.SharedInteractionSystem;
|
|
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
|
using Direction = Robust.Shared.Maths.Direction;
|
|
|
|
namespace Content.Client.Examine
|
|
{
|
|
[UsedImplicitly]
|
|
public sealed class ExamineSystem : ExamineSystemShared
|
|
{
|
|
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
|
[Dependency] private readonly IPlayerManager _playerManager = default!;
|
|
[Dependency] private readonly IEyeManager _eyeManager = default!;
|
|
[Dependency] private readonly VerbSystem _verbSystem = default!;
|
|
[Dependency] private readonly SpriteSystem _sprite = default!;
|
|
|
|
private List<Verb> _verbList = new();
|
|
|
|
public const string StyleClassEntityTooltip = "entity-tooltip";
|
|
|
|
private EntityUid _examinedEntity;
|
|
private Popup? _examineTooltipOpen;
|
|
private ScreenCoordinates _popupPos;
|
|
private CancellationTokenSource? _requestCancelTokenSource;
|
|
private int _idCounter;
|
|
|
|
public override void Initialize()
|
|
{
|
|
base.Initialize();
|
|
|
|
UpdatesOutsidePrediction = true;
|
|
|
|
SubscribeLocalEvent<GetVerbsEvent<ExamineVerb>>(AddExamineVerb);
|
|
|
|
SubscribeNetworkEvent<ExamineSystemMessages.ExamineInfoResponseMessage>(OnExamineInfoResponse);
|
|
|
|
SubscribeLocalEvent<ItemComponent, DroppedEvent>(OnExaminedItemDropped);
|
|
|
|
CommandBinds.Builder
|
|
.Bind(ContentKeyFunctions.ExamineEntity, new PointerInputCmdHandler(HandleExamine, outsidePrediction: true))
|
|
.Register<ExamineSystem>();
|
|
|
|
_idCounter = 0;
|
|
}
|
|
|
|
private void OnExaminedItemDropped(EntityUid item, ItemComponent comp, DroppedEvent args)
|
|
{
|
|
if (!args.User.Valid)
|
|
return;
|
|
if (_examineTooltipOpen == null)
|
|
return;
|
|
|
|
if (item == _examinedEntity && args.User == _playerManager.LocalEntity)
|
|
CloseTooltip();
|
|
}
|
|
|
|
public override void Update(float frameTime)
|
|
{
|
|
if (_examineTooltipOpen is not {Visible: true}) return;
|
|
if (!_examinedEntity.Valid || _playerManager.LocalEntity is not { } player) return;
|
|
|
|
if (!CanExamine(player, _examinedEntity))
|
|
CloseTooltip();
|
|
}
|
|
|
|
public override void Shutdown()
|
|
{
|
|
CommandBinds.Unregister<ExamineSystem>();
|
|
base.Shutdown();
|
|
}
|
|
|
|
public override bool CanExamine(EntityUid examiner, MapCoordinates target, Ignored? predicate = null, EntityUid? examined = null, ExaminerComponent? examinerComp = null)
|
|
{
|
|
if (!Resolve(examiner, ref examinerComp, false))
|
|
return false;
|
|
|
|
if (examinerComp.SkipChecks)
|
|
return true;
|
|
|
|
if (examinerComp.CheckInRangeUnOccluded)
|
|
{
|
|
// TODO fix this. This should be using the examiner's eye component, not eye manager.
|
|
var b = _eyeManager.GetWorldViewbounds();
|
|
if (!b.Contains(target.Position))
|
|
return false;
|
|
}
|
|
|
|
return base.CanExamine(examiner, target, predicate, examined, examinerComp);
|
|
}
|
|
|
|
private bool HandleExamine(in PointerInputCmdHandler.PointerInputCmdArgs args)
|
|
{
|
|
var entity = args.EntityUid;
|
|
|
|
if (!args.EntityUid.IsValid() || !Exists(entity))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (_playerManager.LocalEntity is not { } player ||
|
|
!CanExamine(player, entity))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
DoExamine(entity);
|
|
return true;
|
|
}
|
|
|
|
private void AddExamineVerb(GetVerbsEvent<ExamineVerb> args)
|
|
{
|
|
if (!CanExamine(args.User, args.Target))
|
|
return;
|
|
|
|
// Basic examine verb.
|
|
ExamineVerb verb = new();
|
|
verb.Category = VerbCategory.Examine;
|
|
verb.Priority = 10;
|
|
// Center it on the entity if they use the verb instead.
|
|
verb.Act = () => DoExamine(args.Target, false);
|
|
verb.Text = Loc.GetString("examine-verb-name");
|
|
verb.Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/examine.svg.192dpi.png"));
|
|
verb.ShowOnExamineTooltip = false;
|
|
verb.ClientExclusive = true;
|
|
args.Verbs.Add(verb);
|
|
}
|
|
|
|
private void OnExamineInfoResponse(ExamineSystemMessages.ExamineInfoResponseMessage ev)
|
|
{
|
|
var player = _playerManager.LocalEntity;
|
|
if (player == null)
|
|
return;
|
|
|
|
// Prevent updating a new tooltip.
|
|
if (ev.Id != 0 && ev.Id != _idCounter)
|
|
return;
|
|
|
|
// Tooltips coming in from the server generally prioritize
|
|
// opening at the old tooltip rather than the cursor/another entity,
|
|
// since there's probably one open already if it's coming in from the server.
|
|
var entity = GetEntity(ev.EntityUid);
|
|
|
|
OpenTooltip(player.Value, entity, ev.CenterAtCursor, ev.OpenAtOldTooltip, ev.KnowTarget);
|
|
UpdateTooltipInfo(player.Value, entity, ev.Message, ev.Verbs, getVerbs: false);
|
|
}
|
|
|
|
public override void SendExamineTooltip(EntityUid player, EntityUid target, FormattedMessage message, bool getVerbs, bool centerAtCursor)
|
|
{
|
|
OpenTooltip(player, target, centerAtCursor);
|
|
UpdateTooltipInfo(player, target, message, getVerbs: getVerbs);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Opens the tooltip window and sets spriteview/name/etc, but does
|
|
/// not fill it with information. This is done when the server sends examine info/verbs,
|
|
/// or immediately if it's entirely clientside.
|
|
/// </summary>
|
|
public void OpenTooltip(EntityUid player, EntityUid target, bool centeredOnCursor=true, bool openAtOldTooltip=true, bool knowTarget = true)
|
|
{
|
|
// Close any examine tooltip that might already be opened
|
|
// Before we do that, save its position. We'll prioritize opening any new popups there if
|
|
// openAtOldTooltip is true.
|
|
ScreenCoordinates? oldTooltipPos = _examineTooltipOpen != null ? _popupPos : null;
|
|
CloseTooltip();
|
|
|
|
// cache entity for Update function
|
|
_examinedEntity = target;
|
|
|
|
const float minWidth = 300;
|
|
|
|
if (openAtOldTooltip && oldTooltipPos != null)
|
|
{
|
|
_popupPos = oldTooltipPos.Value;
|
|
}
|
|
else if (centeredOnCursor)
|
|
{
|
|
_popupPos = _userInterfaceManager.MousePositionScaled;
|
|
}
|
|
else
|
|
{
|
|
_popupPos = _eyeManager.CoordinatesToScreen(Transform(target).Coordinates);
|
|
_popupPos = _userInterfaceManager.ScreenToUIPosition(_popupPos);
|
|
}
|
|
|
|
// Actually open the tooltip.
|
|
_examineTooltipOpen = new Popup { MaxWidth = 400 };
|
|
_userInterfaceManager.ModalRoot.AddChild(_examineTooltipOpen);
|
|
var panel = new PanelContainer() { Name = "ExaminePopupPanel" };
|
|
panel.AddStyleClass(StyleClassEntityTooltip);
|
|
panel.ModulateSelfOverride = Color.LightGray.WithAlpha(0.90f);
|
|
_examineTooltipOpen.AddChild(panel);
|
|
|
|
var vBox = new BoxContainer
|
|
{
|
|
Name = "ExaminePopupVbox",
|
|
Orientation = LayoutOrientation.Vertical,
|
|
MaxWidth = _examineTooltipOpen.MaxWidth
|
|
};
|
|
panel.AddChild(vBox);
|
|
|
|
var hBox = new BoxContainer
|
|
{
|
|
Orientation = LayoutOrientation.Horizontal,
|
|
SeparationOverride = 5,
|
|
Margin = new Thickness(6, 0, 6, 0)
|
|
};
|
|
|
|
vBox.AddChild(hBox);
|
|
|
|
if (HasComp<SpriteComponent>(target))
|
|
{
|
|
var spriteView = new SpriteView
|
|
{
|
|
OverrideDirection = Direction.South,
|
|
SetSize = new Vector2(32, 32)
|
|
};
|
|
spriteView.SetEntity(target);
|
|
hBox.AddChild(spriteView);
|
|
}
|
|
|
|
if (knowTarget)
|
|
{
|
|
var itemName = FormattedMessage.EscapeText(Identity.Name(target, EntityManager, player));
|
|
var labelMessage = FormattedMessage.FromMarkupPermissive($"[bold]{itemName}[/bold]");
|
|
var label = new RichTextLabel();
|
|
label.SetMessage(labelMessage);
|
|
hBox.AddChild(label);
|
|
}
|
|
else
|
|
{
|
|
var label = new RichTextLabel();
|
|
label.SetMessage(FormattedMessage.FromMarkupOrThrow("[bold]???[/bold]"));
|
|
hBox.AddChild(label);
|
|
}
|
|
|
|
panel.Measure(Vector2Helpers.Infinity);
|
|
var size = Vector2.Max(new Vector2(minWidth, 0), panel.DesiredSize);
|
|
|
|
_examineTooltipOpen.Open(UIBox2.FromDimensions(_popupPos.Position, size));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Fills the examine tooltip with a message and buttons if applicable.
|
|
/// </summary>
|
|
public void UpdateTooltipInfo(EntityUid player, EntityUid target, FormattedMessage message, List<Verb>? verbs=null, bool getVerbs = true)
|
|
{
|
|
var vBox = _examineTooltipOpen?.GetChild(0).GetChild(0);
|
|
if (vBox == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
foreach (var msg in message.Nodes)
|
|
{
|
|
if (msg.Name != null)
|
|
continue;
|
|
|
|
var text = msg.Value.StringValue ?? "";
|
|
|
|
if (string.IsNullOrWhiteSpace(text))
|
|
continue;
|
|
|
|
var richLabel = new RichTextLabel() { Margin = new Thickness(4, 4, 0, 4)};
|
|
richLabel.SetMessage(message);
|
|
vBox.AddChild(richLabel);
|
|
break;
|
|
}
|
|
|
|
var totalVerbs = _verbSystem.GetLocalVerbs(target, player, typeof(ExamineVerb));
|
|
|
|
// We still need client-exclusive verbs even when the server sends its data in so if that's the case
|
|
// we remove any non-client-exclusive verbs.
|
|
if (!getVerbs)
|
|
{
|
|
_verbList.AddRange(totalVerbs);
|
|
|
|
foreach (var verb in _verbList)
|
|
{
|
|
if (!verb.ClientExclusive)
|
|
{
|
|
totalVerbs.Remove(verb);
|
|
}
|
|
}
|
|
|
|
_verbList.Clear();
|
|
}
|
|
|
|
if (verbs != null)
|
|
{
|
|
totalVerbs.UnionWith(verbs);
|
|
}
|
|
|
|
AddVerbsToTooltip(totalVerbs);
|
|
}
|
|
|
|
private void AddVerbsToTooltip(IEnumerable<Verb> verbs)
|
|
{
|
|
if (_examineTooltipOpen == null)
|
|
return;
|
|
|
|
var buttonsHBox = new BoxContainer
|
|
{
|
|
Name = "ExamineButtonsHBox",
|
|
Orientation = LayoutOrientation.Horizontal,
|
|
HorizontalAlignment = Control.HAlignment.Stretch,
|
|
VerticalAlignment = Control.VAlignment.Bottom,
|
|
};
|
|
|
|
var hoverExamineBox = new BoxContainer
|
|
{
|
|
Name = "HoverExamineHBox",
|
|
Orientation = LayoutOrientation.Horizontal,
|
|
HorizontalAlignment = Control.HAlignment.Left,
|
|
VerticalAlignment = Control.VAlignment.Center,
|
|
HorizontalExpand = true
|
|
};
|
|
|
|
var clickExamineBox = new BoxContainer
|
|
{
|
|
Name = "ClickExamineHBox",
|
|
Orientation = LayoutOrientation.Horizontal,
|
|
HorizontalAlignment = Control.HAlignment.Right,
|
|
VerticalAlignment = Control.VAlignment.Center,
|
|
HorizontalExpand = true
|
|
};
|
|
|
|
// Examine button time
|
|
foreach (var verb in verbs)
|
|
{
|
|
if (verb is not ExamineVerb examine)
|
|
continue;
|
|
|
|
if (examine.Icon == null)
|
|
continue;
|
|
|
|
if (!examine.ShowOnExamineTooltip)
|
|
continue;
|
|
|
|
var button = new ExamineButton(examine, _sprite);
|
|
|
|
if (examine.HoverVerb)
|
|
{
|
|
hoverExamineBox.AddChild(button);
|
|
}
|
|
else
|
|
{
|
|
button.OnPressed += VerbButtonPressed;
|
|
clickExamineBox.AddChild(button);
|
|
}
|
|
}
|
|
|
|
var vbox = _examineTooltipOpen?.GetChild(0).GetChild(0);
|
|
if (vbox == null)
|
|
{
|
|
buttonsHBox.Dispose();
|
|
return;
|
|
}
|
|
|
|
// Remove any existing buttons hbox, in case we generated it from the client
|
|
// then received ones from the server
|
|
var hbox = vbox.Children.Where(c => c.Name == "ExamineButtonsHBox").ToArray();
|
|
if (hbox.Any())
|
|
{
|
|
vbox.Children.Remove(hbox.First());
|
|
}
|
|
buttonsHBox.AddChild(hoverExamineBox);
|
|
buttonsHBox.AddChild(clickExamineBox);
|
|
vbox.AddChild(buttonsHBox);
|
|
}
|
|
|
|
public void VerbButtonPressed(BaseButton.ButtonEventArgs obj)
|
|
{
|
|
if (obj.Button is ExamineButton button)
|
|
{
|
|
_verbSystem.ExecuteVerb(_examinedEntity, button.Verb);
|
|
if (button.Verb.CloseMenu ?? button.Verb.CloseMenuDefault)
|
|
CloseTooltip();
|
|
}
|
|
}
|
|
|
|
public void DoExamine(EntityUid entity, bool centeredOnCursor = true, EntityUid? userOverride = null)
|
|
{
|
|
var playerEnt = userOverride ?? _playerManager.LocalEntity;
|
|
if (playerEnt == null)
|
|
return;
|
|
|
|
FormattedMessage message;
|
|
|
|
OpenTooltip(playerEnt.Value, entity, centeredOnCursor, false);
|
|
|
|
// Always update tooltip info from client first.
|
|
// If we get it wrong, server will correct us later anyway.
|
|
// This will usually be correct (barring server-only components, which generally only adds, not replaces text)
|
|
message = GetExamineText(entity, playerEnt);
|
|
UpdateTooltipInfo(playerEnt.Value, entity, message);
|
|
|
|
if (!IsClientSide(entity))
|
|
{
|
|
// Ask server for extra examine info.
|
|
unchecked
|
|
{
|
|
_idCounter += 1;
|
|
}
|
|
RaiseNetworkEvent(new ExamineSystemMessages.RequestExamineInfoMessage(GetNetEntity(entity), _idCounter, true));
|
|
}
|
|
|
|
RaiseLocalEvent(entity, new ClientExaminedEvent(entity, playerEnt.Value));
|
|
}
|
|
|
|
private void CloseTooltip()
|
|
{
|
|
if (_examineTooltipOpen != null)
|
|
{
|
|
foreach (var control in _examineTooltipOpen.Children)
|
|
{
|
|
if (control is ExamineButton button)
|
|
{
|
|
button.OnPressed -= VerbButtonPressed;
|
|
}
|
|
}
|
|
_examineTooltipOpen.Dispose();
|
|
_examineTooltipOpen = null;
|
|
}
|
|
|
|
if (_requestCancelTokenSource != null)
|
|
{
|
|
_requestCancelTokenSource.Cancel();
|
|
_requestCancelTokenSource = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// An entity was examined on the client.
|
|
/// </summary>
|
|
public sealed class ClientExaminedEvent : EntityEventArgs
|
|
{
|
|
/// <summary>
|
|
/// The entity performing the examining.
|
|
/// </summary>
|
|
public readonly EntityUid Examiner;
|
|
|
|
/// <summary>
|
|
/// Entity being examined, for broadcast event purposes.
|
|
/// </summary>
|
|
public readonly EntityUid Examined;
|
|
|
|
public ClientExaminedEvent(EntityUid examined, EntityUid examiner)
|
|
{
|
|
Examined = examined;
|
|
Examiner = examiner;
|
|
}
|
|
}
|
|
}
|