3 using Microsoft.Xna.Framework;
5 using System.Collections.Generic;
6 using System.Globalization;
36 private readonly List<LimbPos> limbPositions =
new List<LimbPos>();
43 private Vector2 userPos;
49 private Item focusTarget;
50 private float targetRotation;
54 get {
return userPos; }
55 set { userPos = value; }
63 public IEnumerable<LimbPos>
LimbPositions {
get {
return limbPositions; } }
65 [
Editable,
Serialize(
false,
IsPropertySaveable.No, description:
"When enabled, the item will continuously send out a signal and interacting with it will flip the signal (making the item behave like a switch). When disabled, the item will simply send out a signal when interacted with.", alwaysUseInstanceValues:
true)]
72 private string output;
74 Serialize(
"1",
IsPropertySaveable.Yes, description:
"The signal sent when the controller is being activated or is toggled on. If empty, no signal is sent.", alwaysUseInstanceValues:
true)]
77 get {
return output; }
80 if (value ==
null || value == output) {
return; }
83 if (!value.IsNullOrEmpty()) {
IsActive =
true; }
87 private string falseOutput;
89 Serialize(
"0",
IsPropertySaveable.Yes, description:
"The signal sent when the controller is toggled off. If empty, no signal is sent. Only valid if IsToggle is true.", alwaysUseInstanceValues:
true)]
92 get {
return falseOutput; }
95 if (value ==
null || value == falseOutput) {
return; }
98 if (!value.IsNullOrEmpty()) {
IsActive =
true; }
104 Serialize(
false,
IsPropertySaveable.No, description:
"Whether the item is toggled on/off. Only valid if IsToggle is set to true.", alwaysUseInstanceValues:
true)]
107 get {
return state; }
113 string newOutput = state ? output : falseOutput;
114 IsActive = !
string.IsNullOrEmpty(newOutput);
119 [
Serialize(
true,
IsPropertySaveable.No, description:
"Should the HUD (inventory, health bar, etc) be hidden when this item is selected.")]
141 [
Serialize(
true,
IsPropertySaveable.No, description:
"Can another character select this controller when another character has already selected it?")]
148 [
Serialize(
true,
IsPropertySaveable.No, description:
"Can another character select this controller when a bot has already selected it?")]
157 get {
return limbPositions.Count > 0; }
194 : base(
item, element)
198 LoadLimbPositions(element);
233 if (userPos != Vector2.Zero)
239 if (diff.LengthSquared() > 30.0f * 30.0f)
259 if (Math.Abs(diff.X) > 20.0f)
264 else if (Math.Abs(diff.X) > 0.1f)
272 else if (Math.Abs(diff.X) > 10.0f)
286 if (limbPositions.Count == 0) {
return; }
301 foreach (
LimbPos lb
in limbPositions)
304 if (limb ==
null || !limb.
body.
Enabled) {
continue; }
333 private double lastUsed;
337 if (activator != user)
347 if (
IsToggle && (activator ==
null || lastUsed < Timing.TotalTime - 0.1))
353 item.CreateServerEvent(
this);
357 else if (!
string.IsNullOrEmpty(output))
362 lastUsed = Timing.TotalTime;
369 if (user != character)
378 if (character ==
null)
385 if (focusTarget ==
null)
388 Vector2 offset = character.CursorWorldPosition - centerPos;
389 offset.Y = -offset.Y;
390 targetRotation = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(offset));
394 character.ViewTarget = focusTarget;
399 Lights.LightManager.ViewTarget = focusTarget;
406 if (!character.IsRemotePlayer || character.ViewTarget == focusTarget)
408 Vector2 centerPos =
new Vector2(focusTarget.
WorldRect.Center.X, focusTarget.
WorldRect.Center.Y);
409 if (focusTarget.GetComponent<
Turret>() is { } turret)
411 centerPos =
new Vector2(focusTarget.
WorldRect.X + turret.TransformedBarrelPos.X, focusTarget.
WorldRect.Y - turret.TransformedBarrelPos.Y);
413 Vector2 offset = character.CursorWorldPosition - centerPos;
414 offset.Y = -offset.Y;
415 targetRotation = MathUtils.WrapAngleTwoPi(MathUtils.VectorToAngle(offset));
422 var positionOut =
item.
Connections?.Find(c => c.Name ==
"position_out");
423 if (positionOut ==
null) {
return null; }
425 item.
SendSignal(
new Signal(MathHelper.ToDegrees(targetRotation).ToString(
"G", CultureInfo.InvariantCulture), sender: user), positionOut);
436 foreach (var recipientPanel
in item.GetConnectedComponentsRecursive<
ConnectionPanel>(positionOut, allowTraversingBackwards:
false))
438 if (recipientPanel.Item.Condition <= 0.0f) {
continue; }
439 if (recipientPanel.Item.Prefab.FocusOnSelected)
441 return recipientPanel.Item;
459 item.CreateServerEvent(
this);
463 else if (!
string.IsNullOrEmpty(output))
473 private void CancelUsing(
Character character)
475 if (character ==
null || character.
Removed) {
return; }
477 foreach (LimbPos lb
in limbPositions)
480 if (limb ==
null) {
continue; }
487 if (character.
AnimController is HumanoidAnimController humanoidAnim)
489 humanoidAnim.LockFlipping(0.5f);
501 item.CreateServerEvent(
this);
507 if (activator ==
null || activator.
Removed) {
return false; }
517 if (user !=
null && !user.
Removed)
519 if (user == activator)
544 item.CreateServerEvent(
this);
546 if (!
string.IsNullOrEmpty(output))
553 public override void FlipX(
bool relativeToSub)
563 public override void FlipY(
bool relativeToSub)
567 for (
int i = 0; i < limbPositions.Count; i++)
569 float diff = (
item.
Rect.Y + limbPositions[i].Position.Y) -
item.
Rect.Center.Y;
573 limbPositions[i].Position.X,
575 limbPositions[i] =
new LimbPos(limbPositions[i].
LimbType, flippedPos, limbPositions[i].AllowUsingLimb);
582 return base.HasAccess(character);
585 partial
void HideHUDs(
bool value);
587 public override XElement
Save(XElement parentElement)
589 return SaveLimbPositions(base.Save(parentElement));
594 base.Load(componentElement, usePrefabValues, idRemap, isItemSwap);
597 LoadLimbPositions(componentElement);
601 private XElement SaveLimbPositions(XElement element)
610 foreach (var limbPos
in limbPositions)
612 element.Add(
new XElement(
"limbposition",
613 new XAttribute(
"limb", limbPos.LimbType),
614 new XAttribute(
"position", XMLExtensions.Vector2ToString(limbPos.Position)),
615 new XAttribute(
"allowusinglimb", limbPos.AllowUsingLimb)));
625 private void LoadLimbPositions(ContentXElement element)
627 limbPositions.Clear();
628 foreach (var subElement
in element.Elements())
630 if (subElement.Name !=
"limbposition") {
continue; }
631 string limbStr = subElement.GetAttributeString(
"limb",
"");
632 if (!Enum.TryParse(subElement.GetAttribute(
"limb").Value, out
LimbType limbType))
634 DebugConsole.ThrowError($
"Error in item \"{item.Name}\" - {limbStr} is not a valid limb type.",
635 contentPackage: element.ContentPackage);
639 LimbPos limbPos =
new LimbPos(limbType,
640 subElement.GetAttributeVector2(
"position", Vector2.Zero),
641 subElement.GetAttributeBool(
"allowusinglimb",
false));
642 limbPositions.Add(limbPos);
643 if (!limbPos.AllowUsingLimb)
655 private void FlipLimbPositions()
657 for (
int i = 0; i < limbPositions.Count; i++)
664 limbPositions[i].Position.Y);
665 limbPositions[i] =
new LimbPos(limbPositions[i].
LimbType, flippedPos, limbPositions[i].AllowUsingLimb);
bool CanInteractWith(Character c, float maxDist=200.0f, bool checkVisibility=true, bool skipDistanceCheck=false)
Item????????? SelectedItem
The primary selected item. It can be any device that character interacts with. This excludes items li...
CharacterInventory Inventory
bool HasSelectedAnotherSecondaryItem(Item item)
static Character? Controlled
Item SelectedSecondaryItem
The secondary selected item. It's an item other than a device (see SelectedItem), e....
bool IsAnySelectedItem(Item item)
Is the item either the primary or the secondary selected item?
readonly AnimController AnimController
Item GetItemInLimbSlot(InvSlotType limbSlot)
string? GetAttributeString(string key, string? def)
Vector2 GetAttributeVector2(string key, in Vector2 def)
virtual Vector2 WorldPosition
static GameSession?? GameSession
static SubEditorScreen SubEditorScreen
static NetworkMember NetworkMember
static GameModePreset TestMode
List< Connection > Connections
Inventory ParentInventory
float OffsetOnSelectedMultiplier
bool IsInteractable(Character character)
Returns interactibility based on whether the character is on a player team
List< Connection > LastSentSignalRecipients
A list of connections the last signal sent by this item went through
void SendSignal(string signal, string connectionName)
override bool SecondaryUse(float deltaTime, Character character=null)
override bool Use(float deltaTime, Character activator=null)
bool UserInCorrectPosition
override void FlipX(bool relativeToSub)
bool AllowSelectingWhenSelectedByBot
bool ControlCharacterPose
override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap, bool isItemSwap)
IEnumerable< LimbPos > LimbPositions
override void FlipY(bool relativeToSub)
override bool HasAccess(Character character)
Only checks if any of the Picked requirements are matched (used for checking id card(s))....
bool NonInteractableWhenFlippedY
bool AllowSelectingWhenSelectedByOther
override void OnItemLoaded()
Called when all the components of the item have been loaded. Use to initialize connections between co...
override bool Select(Character activator)
override XElement Save(XElement parentElement)
bool NonInteractableWhenFlippedX
override bool Pick(Character picker)
a Character has picked the item
Controller(Item item, ContentXElement element)
override void Update(float deltaTime, Camera cam)
The base class for components holding the different functionalities of the item
void ApplyStatusEffects(ActionType type, float deltaTime, Character character=null, Limb targetLimb=null, Entity useTarget=null, Character user=null, Vector2? worldPosition=null, float afflictionMultiplier=1.0f)
void PlaySound(ActionType type, Character user=null)
readonly ContentXElement originalElement
virtual bool UpdateWhenInactive
Dictionary< Identifier, SerializableProperty > SerializableProperties
LimbPos(LimbType limbType, Vector2 position, bool allowUsingLimb)
Vector2 PullJointWorldAnchorB
void ResetPullJoints(Func< Limb, bool > condition=null)
Limb GetLimb(LimbType limbType, bool excludeSevered=true)
Note that if there are multiple limbs of the same type, only the first (valid) limb is returned.
Interface for entities that the server can send events to the clients
ActionType
ActionTypes define when a StatusEffect is executed.