/// <summary> /// Add an alt-click interaction that cycles through delays. /// </summary> private void OnGetAltVerbs(EntityUid uid, OnUseTimerTriggerComponent component, GetVerbsEvent <AlternativeVerb> args) { if (!args.CanInteract || !args.CanAccess) { return; } if (component.DelayOptions == null || component.DelayOptions.Count == 1) { return; } args.Verbs.Add(new AlternativeVerb() { Category = TimerOptions, Text = Loc.GetString("verb-trigger-timer-cycle"), Act = () => CycleDelay(component, args.User), Priority = 1 }); foreach (var option in component.DelayOptions) { if (MathHelper.CloseTo(option, component.Delay)) { args.Verbs.Add(new AlternativeVerb() { Category = TimerOptions, Text = Loc.GetString("verb-trigger-timer-set-current", ("time", option)), Disabled = true, Priority = (int)(-100 * option) });
private void AddEatVerb(EntityUid uid, FoodComponent component, GetVerbsEvent <InteractionVerb> ev) { if (component.CancelToken != null) { return; } if (uid == ev.User || !ev.CanInteract || !ev.CanAccess || !EntityManager.TryGetComponent(ev.User, out SharedBodyComponent? body) || !_bodySystem.TryGetComponentsOnMechanisms <StomachComponent>(ev.User, out var stomachs, body)) { return; } if (EntityManager.TryGetComponent <MobStateComponent>(uid, out var mobState) && mobState.IsAlive()) { return; } InteractionVerb verb = new() { Act = () => { TryFeed(uid, ev.User, component); }, IconTexture = "/Textures/Interface/VerbIcons/cutlery.svg.192dpi.png", Text = Loc.GetString("food-system-verb-eat"), Priority = -1 }; ev.Verbs.Add(verb); }
private void AddOpenUiVerb(EntityUid uid, ActivatableUIComponent component, GetVerbsEvent <ActivationVerb> args) { if (!args.CanAccess) { return; } if (component.RequireHands && args.Hands == null) { return; } if (component.InHandsOnly && args.Using != uid) { return; } if (!args.CanInteract && (!component.AllowSpectator || !HasComp <GhostComponent>(args.User))) { return; } ActivationVerb verb = new(); verb.Act = () => InteractUI(args.User, component); verb.Text = Loc.GetString(component.VerbText); // TODO VERBS add "open UI" icon? args.Verbs.Add(verb); }
private void OnGetAlternativeVerbs(GetVerbsEvent <AlternativeVerb> ev) { if (!HasComp <SharedGhostComponent>(ev.User)) { return; } if (ev.User == ev.Target) { return; } var verb = new AlternativeVerb { Priority = 10, Act = (() => { StartFollowingEntity(ev.User, ev.Target); }), Impact = LogImpact.Low, Text = Loc.GetString("verb-follow-text"), IconTexture = "/Textures/Interface/VerbIcons/open.svg.192dpi.png", }; ev.Verbs.Add(verb); }
private void OnGetExamineVerbs(EntityUid uid, CableComponent component, GetVerbsEvent <ExamineVerb> args) { // Must be in details range to try this. // Theoretically there should be a separate range at which a multitool works, but this does just fine. if (_examineSystem.IsInDetailsRange(args.User, args.Target)) { var held = args.Using; // Pulsing is hardcoded here because I don't think it needs to be more complex than that right now. // Update if I'm wrong. var enabled = held != null && _toolSystem.HasQuality(held.Value, "Pulsing"); var verb = new ExamineVerb { Disabled = !enabled, Message = Loc.GetString("cable-multitool-system-verb-tooltip"), Text = Loc.GetString("cable-multitool-system-verb-name"), Category = VerbCategory.Examine, IconTexture = "/Textures/Interface/VerbIcons/zap.svg.192dpi.png", Act = () => { var markup = FormattedMessage.FromMarkup(GenerateCableMarkup(uid)); _examineSystem.SendExamineTooltip(args.User, uid, markup, false, false); } }; args.Verbs.Add(verb); } }
private void AddSpinVerb(EntityUid uid, RevolverBarrelComponent component, GetVerbsEvent <AlternativeVerb> args) { if (args.Hands == null || !args.CanAccess || !args.CanInteract) { return; } if (component.Capacity <= 1 || component.ShotsLeft == 0) { return; } AlternativeVerb verb = new() { Text = Loc.GetString("spin-revolver-verb-get-data-text"), IconTexture = "/Textures/Interface/VerbIcons/refresh.svg.192dpi.png", Act = () => { SpinRevolver(component); component.Owner.PopupMessage(args.User, Loc.GetString("spin-revolver-verb-on-activate")); } }; args.Verbs.Add(verb); }
private void AddPickupVerb(EntityUid uid, ItemComponent component, GetVerbsEvent <InteractionVerb> args) { if (args.Hands == null || args.Using != null || !args.CanAccess || !args.CanInteract) //|| //!_handsSystem.CanPickupAnyHand(args.User, args.Target, handsComp: args.Hands, item: component)) { return; } InteractionVerb verb = new(); // TODO ITEM //verb.Act = () => _handsSystem.TryPickupAnyHand(args.User, args.Target, checkActionBlocker: false, // handsComp: args.Hands, item: component); verb.IconTexture = "/Textures/Interface/VerbIcons/pickup.svg.192dpi.png"; // if the item already in a container (that is not the same as the user's), then change the text. // this occurs when the item is in their inventory or in an open backpack _container.TryGetContainingContainer(args.User, out var userContainer); if (_container.TryGetContainingContainer(args.Target, out var container) && container != userContainer) { verb.Text = Loc.GetString("pick-up-verb-get-data-text-inventory"); } else { verb.Text = Loc.GetString("pick-up-verb-get-data-text"); } args.Verbs.Add(verb); }
private void AddStyleVerb(EntityUid uid, SwappableInstrumentComponent component, GetVerbsEvent <AlternativeVerb> args) { if (!args.CanInteract || !args.CanAccess || component.InstrumentList.Count <= 1) { return; } if (!TryComp <SharedInstrumentComponent>(uid, out var instrument)) { return; } var priority = 0; foreach (var entry in component.InstrumentList) { AlternativeVerb selection = new() { Text = entry.Key, Category = VerbCategory.InstrumentStyle, Priority = priority, Act = () => { _sharedInstrument.SetInstrumentProgram(instrument, entry.Value.Item1, entry.Value.Item2); _popup.PopupEntity(Loc.GetString("swappable-instrument-component-style-set", ("style", entry.Key)), args.User, Filter.Entities(args.User)); } }; priority--; args.Verbs.Add(selection); } } }
private void AddSpillVerb(EntityUid uid, SpillableComponent component, GetVerbsEvent <Verb> args) { if (!args.CanAccess || !args.CanInteract) { return; } if (!_solutionContainerSystem.TryGetDrainableSolution(args.Target, out var solution)) { return; } if (solution.DrainAvailable == FixedPoint2.Zero) { return; } Verb verb = new(); verb.Text = Loc.GetString("spill-target-verb-get-data-text"); // TODO VERB ICONS spill icon? pouring out a glass/beaker? verb.Act = () => { var puddleSolution = _solutionContainerSystem.SplitSolution(args.Target, solution, solution.DrainAvailable); SpillAt(puddleSolution, Transform(args.Target).Coordinates, "PuddleSmear"); }; verb.Impact = LogImpact.Medium; // dangerous reagent reaction are logged separately. args.Verbs.Add(verb); }
private void OnVerb(EntityUid uid, DockingComponent component, GetVerbsEvent <InteractionVerb> args) { if (!args.CanInteract || !args.CanAccess) { return; } InteractionVerb?verb; // TODO: Have it open the UI and have the UI do this. if (!component.Docked && TryComp(uid, out PhysicsComponent? body) && TryComp(uid, out TransformComponent? xform)) { DockingComponent?otherDock = null; if (component.Enabled) { otherDock = GetDockable(body, xform); } verb = new InteractionVerb { Disabled = otherDock == null, Text = Loc.GetString("docking-component-dock"), Act = () => { if (otherDock == null) { return; } TryDock(component, otherDock); } }; } else if (component.Docked) { verb = new InteractionVerb { Disabled = !component.Docked, Text = Loc.GetString("docking-component-undock"), Act = () => { if (component.DockedWith == null || !component.Enabled) { return; } Undock(component); } }; } else { return; } args.Verbs.Add(verb); }
private void AddPointingVerb(GetVerbsEvent <Verb> args) { // Really this could probably be a properly predicted event, but that requires reworking pointing. For now // I'm just adding this verb exclusively to clients so that the verb-loading pop-in on the verb menu isn't // as bad. Important for this verb seeing as its usually an option on just about any entity. if (HasComp <PointingArrowComponent>(args.Target)) { // this is a pointing arrow. no pointing here... return; } // Can the user point? Checking mob state directly instead of some action blocker, as many action blockers are blocked for // ghosts and there is no obvious choice for pointing (unless ghosts CanEmote?). if (TryComp(args.User, out MobStateComponent? mob) && mob.IsIncapacitated()) { return; } // We won't check in range or visibility, as this verb is currently only executable via the context menu, // and that should already have checked that, as well as handling the FOV-toggle stuff. Verb verb = new() { Text = Loc.GetString("pointing-verb-get-data-text"), IconTexture = "/Textures/Interface/VerbIcons/point.svg.192dpi.png", ClientExclusive = true, Act = () => RaiseNetworkEvent(new PointingAttemptEvent(args.Target)) }; args.Verbs.Add(verb); } }
private void AddRotateVerbs(EntityUid uid, RotatableComponent component, GetVerbsEvent <Verb> args) { if (!args.CanAccess || !args.CanInteract || Transform(uid).NoLocalRotation) // Good ol prototype inheritance, eh? { return; } // Check if the object is anchored, and whether we are still allowed to rotate it. if (!component.RotateWhileAnchored && EntityManager.TryGetComponent(component.Owner, out IPhysBody? physics) && physics.BodyType == BodyType.Static) { return; } Verb resetRotation = new () { Act = () => EntityManager.GetComponent <TransformComponent>(component.Owner).LocalRotation = Angle.Zero, Category = VerbCategory.Rotate, IconTexture = "/Textures/Interface/VerbIcons/refresh.svg.192dpi.png", Text = "Reset", Priority = -2, // show CCW, then CW, then reset CloseMenu = false, }; args.Verbs.Add(resetRotation); // rotate clockwise Verb rotateCW = new() { Act = () => EntityManager.GetComponent <TransformComponent>(component.Owner).LocalRotation -= component.Increment, Category = VerbCategory.Rotate, IconTexture = "/Textures/Interface/VerbIcons/rotate_cw.svg.192dpi.png", Priority = -1, CloseMenu = false, // allow for easy double rotations. }; args.Verbs.Add(rotateCW); // rotate counter-clockwise Verb rotateCCW = new() { Act = () => EntityManager.GetComponent <TransformComponent>(component.Owner).LocalRotation += component.Increment, Category = VerbCategory.Rotate, IconTexture = "/Textures/Interface/VerbIcons/rotate_ccw.svg.192dpi.png", Priority = 0, CloseMenu = false, // allow for easy double rotations. }; args.Verbs.Add(rotateCCW); }
private void OnDoorAltVerb(EntityUid uid, DoorComponent component, GetVerbsEvent <AlternativeVerb> args) { if (!args.CanInteract || !TryComp <ToolComponent>(args.User, out var tool) || !tool.Qualities.Contains(component.PryingQuality)) { return; } args.Verbs.Add(new AlternativeVerb() { Text = "Pry door", Impact = LogImpact.Low, Act = () => TryPryDoor(uid, args.User, args.User, component, true), }); }
private void AddOpenUIVerb(EntityUid uid, GasTankComponent component, GetVerbsEvent <ActivationVerb> args) { if (!args.CanAccess || !EntityManager.TryGetComponent <ActorComponent?>(args.User, out var actor)) { return; } ActivationVerb verb = new(); verb.Act = () => component.OpenInterface(actor.PlayerSession); verb.Text = Loc.GetString("control-verb-open-control-panel-text"); // TODO VERBS add "open UI" icon? args.Verbs.Add(verb); }
private void AddFlipVerb(EntityUid uid, FlippableComponent component, GetVerbsEvent <Verb> args) { if (!args.CanAccess || !args.CanInteract || component.MirrorEntity == null) { return; } Verb verb = new(); verb.Act = () => TryFlip(component, args.User); verb.Text = Loc.GetString("flippable-verb-get-data-text"); // TODO VERB ICONS Add Uno reverse card style icon? args.Verbs.Add(verb); }
private void AddToggleVerb(EntityUid uid, MagbootsComponent component, GetVerbsEvent <ActivationVerb> args) { if (!args.CanAccess || !args.CanInteract) { return; } ActivationVerb verb = new(); verb.Text = Loc.GetString("toggle-magboots-verb-get-data-text"); verb.Act = () => component.On = !component.On; // TODO VERB ICON add toggle icon? maybe a computer on/off symbol? args.Verbs.Add(verb); }
private void AddEjectVerbs(EntityUid uid, ItemSlotsComponent itemSlots, GetVerbsEvent <AlternativeVerb> args) { if (args.Hands == null || !args.CanAccess || !args.CanInteract) { return; } foreach (var slot in itemSlots.Slots.Values) { if (slot.EjectOnInteract) { // For this item slot, ejecting/inserting is a primary interaction. Instead of an eject category // alt-click verb, there will be a "Take item" primary interaction verb. continue; } if (!CanEject(slot)) { continue; } if (!_actionBlockerSystem.CanPickup(args.User, slot.Item !.Value)) { continue; } var verbSubject = slot.Name != string.Empty ? Loc.GetString(slot.Name) : EntityManager.GetComponent <MetaDataComponent>(slot.Item.Value).EntityName ?? string.Empty; AlternativeVerb verb = new(); verb.IconEntity = slot.Item; verb.Act = () => TryEjectToHands(uid, slot, args.User, excludeUserAudio: true); if (slot.EjectVerbText == null) { verb.Text = verbSubject; verb.Category = VerbCategory.Eject; } else { verb.Text = Loc.GetString(slot.EjectVerbText); } verb.Priority = slot.Priority; args.Verbs.Add(verb); } }
private void AddToggleLockVerb(EntityUid uid, LockComponent component, GetVerbsEvent <AlternativeVerb> args) { if (!args.CanAccess || !args.CanInteract || !CanToggleLock(uid, args.User)) { return; } AlternativeVerb verb = new(); verb.Act = component.Locked ? () => TryUnlock(uid, args.User, component) : () => TryLock(uid, args.User, component); verb.Text = Loc.GetString(component.Locked ? "toggle-lock-verb-unlock" : "toggle-lock-verb-lock"); // TODO VERB ICONS need padlock open/close icons. args.Verbs.Add(verb); }
private void AddAdminVerbs(GetVerbsEvent <Verb> args) { // Currently this is only the ViewVariables verb, but more admin-UI related verbs can be added here. // View variables verbs if (_clientConGroupController.CanViewVar()) { Verb verb = new(); verb.Category = VerbCategory.Debug; verb.Text = "View Variables"; verb.IconTexture = "/Textures/Interface/VerbIcons/vv.svg.192dpi.png"; verb.Act = () => _clientConsoleHost.ExecuteCommand($"vv {args.Target}"); verb.ClientExclusive = true; // opening VV window is client-side. Don't ask server to run this verb. args.Verbs.Add(verb); } }
private void AddWipeVerb(EntityUid uid, PAIComponent pai, GetVerbsEvent <ActivationVerb> args) { if (!args.CanAccess || !args.CanInteract) { return; } if (EntityManager.TryGetComponent <MindComponent>(uid, out var mind) && mind.HasMind) { ActivationVerb verb = new(); verb.Text = Loc.GetString("pai-system-wipe-device-verb-text"); verb.Act = () => { if (pai.Deleted) { return; } // Wiping device :( // The shutdown of the Mind should cause automatic reset of the pAI during OnMindRemoved // EDIT: But it doesn't!!!! Wtf? Do stuff manually if (EntityManager.HasComponent <MindComponent>(uid)) { EntityManager.RemoveComponent <MindComponent>(uid); _popupSystem.PopupEntity(Loc.GetString("pai-system-wiped-device"), uid, Filter.Entities(args.User)); PAITurningOff(uid); } }; args.Verbs.Add(verb); } else if (EntityManager.HasComponent <GhostTakeoverAvailableComponent>(uid)) { ActivationVerb verb = new(); verb.Text = Loc.GetString("pai-system-stop-searching-verb-text"); verb.Act = () => { if (pai.Deleted) { return; } if (EntityManager.HasComponent <GhostTakeoverAvailableComponent>(uid)) { EntityManager.RemoveComponent <GhostTakeoverAvailableComponent>(uid); _popupSystem.PopupEntity(Loc.GetString("pai-system-stopped-searching"), uid, Filter.Entities(args.User)); PAITurningOff(uid); } }; args.Verbs.Add(verb); } }
private void AddVerbs(EntityUid uid, SurveillanceCameraComponent component, GetVerbsEvent <AlternativeVerb> verbs) { if (!_actionBlocker.CanInteract(verbs.User, uid)) { return; } if (component.NameSet && component.NetworkSet) { return; } AlternativeVerb verb = new(); verb.Text = Loc.GetString("surveillance-camera-setup"); verb.Act = () => OpenSetupInterface(uid, verbs.User, component); verbs.Verbs.Add(verb); }
private void OnAltVerb(EntityUid uid, GunComponent component, GetVerbsEvent <AlternativeVerb> args) { if (!args.CanAccess || !args.CanInteract || component.SelectedMode == component.AvailableModes) { return; } var nextMode = GetNextMode(component); AlternativeVerb verb = new() { Act = () => SelectFire(component, nextMode, args.User), Text = Loc.GetString("gun-selector-verb", ("mode", GetLocSelector(nextMode))), IconTexture = "/Textures/Interface/VerbIcons/fold.svg.192dpi.png", }; args.Verbs.Add(verb); }
private void AddFoldVerb(EntityUid uid, FoldableComponent component, GetVerbsEvent <AlternativeVerb> args) { if (!args.CanAccess || !args.CanInteract || args.Hands == null || !CanToggleFold(uid, component)) { return; } AlternativeVerb verb = new() { Act = () => TryToggleFold(component), Text = component.IsFolded ? Loc.GetString("unfold-verb") : Loc.GetString("fold-verb"), IconTexture = "/Textures/Interface/VerbIcons/fold.svg.192dpi.png", // If the object is unfolded and they click it, they want to fold it, if it's folded, they want to pick it up Priority = component.IsFolded ? 0 : 2, }; args.Verbs.Add(verb); }
/// <summary> /// Add a verb that allows the player to start playing a tabletop game. /// </summary> private void AddPlayGameVerb(EntityUid uid, TabletopGameComponent component, GetVerbsEvent <ActivationVerb> args) { if (!args.CanAccess || !args.CanInteract) { return; } if (!EntityManager.TryGetComponent <ActorComponent?>(args.User, out var actor)) { return; } ActivationVerb verb = new(); verb.Text = Loc.GetString("tabletop-verb-play-game"); verb.IconTexture = "/Textures/Interface/VerbIcons/die.svg.192dpi.png"; verb.Act = () => OpenSessionFor(actor.PlayerSession, uid); args.Verbs.Add(verb); }
private void AddWakeVerb(EntityUid uid, SleepingComponent component, GetVerbsEvent <AlternativeVerb> args) { if (!args.CanInteract || !args.CanAccess) { return; } AlternativeVerb verb = new() { Act = () => { TryWaking(args.Target, user: args.User); }, Text = Loc.GetString("action-name-wake"), Priority = 2 }; args.Verbs.Add(verb); }
// Probably needs combining with magazines in future given the common functionality. private void OnAmmoBoxAltVerbs(EntityUid uid, AmmoBoxComponent component, GetVerbsEvent <AlternativeVerb> args) { if (args.Hands == null || !args.CanAccess || !args.CanInteract) { return; } if (component.AmmoLeft == 0) { return; } AlternativeVerb verb = new() { Text = Loc.GetString("dump-vert-get-data-text"), IconTexture = "/Textures/Interface/VerbIcons/eject.svg.192dpi.png", Act = () => AmmoBoxEjectContents(component, 10) }; args.Verbs.Add(verb); }
private void OnGetExamineVerbs(EntityUid uid, IdExaminableComponent component, GetVerbsEvent <ExamineVerb> args) { var detailsRange = _examineSystem.IsInDetailsRange(args.User, uid); var info = GetInfo(component.Owner) ?? Loc.GetString("id-examinable-component-verb-no-id"); var verb = new ExamineVerb() { Act = () => { var markup = FormattedMessage.FromMarkup(info); _examineSystem.SendExamineTooltip(args.User, uid, markup, false, false); }, Text = Loc.GetString("id-examinable-component-verb-text"), Category = VerbCategory.Examine, Disabled = !detailsRange, Message = Loc.GetString("id-examinable-component-verb-disabled"), IconTexture = "/Textures/Interface/VerbIcons/information.svg.192dpi.png" }; args.Verbs.Add(verb); }
private void AddToggleWieldVerb(EntityUid uid, WieldableComponent component, GetVerbsEvent <InteractionVerb> args) { if (args.Hands == null || !args.CanAccess || !args.CanInteract) { return; } // TODO VERB TOOLTIPS Make CanWield or some other function return string, set as verb tooltip and disable // verb. Or just don't add it to the list if the action is not executable. // TODO VERBS ICON + localization InteractionVerb verb = new() { Text = component.Wielded ? "Unwield" : "Wield", Act = component.Wielded ? () => AttemptUnwield(component.Owner, component, args.User) : () => AttemptWield(component.Owner, component, args.User) }; args.Verbs.Add(verb); }
private void OnStackAlternativeInteract(EntityUid uid, StackComponent stack, GetVerbsEvent <AlternativeVerb> args) { if (!args.CanAccess || !args.CanInteract) { return; } AlternativeVerb halve = new() { Text = Loc.GetString("comp-stack-split-halve"), Category = VerbCategory.Split, Act = () => UserSplit(uid, args.User, stack.Count / 2, stack), Priority = 1 }; args.Verbs.Add(halve); var priority = 0; foreach (var amount in DefaultSplitAmounts) { if (amount >= stack.Count) { continue; } AlternativeVerb verb = new() { Text = amount.ToString(), Category = VerbCategory.Split, Act = () => UserSplit(uid, args.User, amount, stack), // we want to sort by size, not alphabetically by the verb text. Priority = priority }; priority--; args.Verbs.Add(verb); } }
private void AddUtilityVerbs(EntityUid uid, DumpableComponent dumpable, GetVerbsEvent <UtilityVerb> args) { if (!args.CanAccess || !args.CanInteract) { return; } if (!TryComp <ServerStorageComponent>(uid, out var storage) || storage.StoredEntities == null || storage.StoredEntities.Count == 0) { return; } if (HasComp <DisposalUnitComponent>(args.Target)) { UtilityVerb verb = new() { Act = () => { StartDoAfter(uid, args.Target, args.User, dumpable, storage); }, Text = Loc.GetString("dump-disposal-verb-name", ("unit", args.Target)), IconEntity = uid }; args.Verbs.Add(verb); } if (HasComp <PlaceableSurfaceComponent>(args.Target)) { UtilityVerb verb = new() { Act = () => { StartDoAfter(uid, args.Target, args.User, dumpable, storage); }, Text = Loc.GetString("dump-placeable-verb-name", ("surface", args.Target)), IconEntity = uid }; args.Verbs.Add(verb); } }