1 using Microsoft.Xna.Framework;
3 using System.Collections.Generic;
10 using System.Collections.Immutable;
35 get {
return _sprite; }
38 if (value == _sprite) {
return; }
76 public float Scale {
get;
private set; }
84 get {
return _wearableComponent; }
87 if (value == _wearableComponent) {
return; }
88 if (_wearableComponent !=
null)
90 _wearableComponent.
Remove();
92 _wearableComponent = value;
95 public string Sound {
get;
private set; }
104 if (_lightComponents ==
null)
106 _lightComponents =
new List<LightComponent>();
108 return _lightComponents;
111 private List<LightComponent> _lightComponents;
122 get {
return _picker; }
125 if (value == _picker) {
return; }
159 Variant = Math.Max(variant, 0);
171 $
"{Path.GetDirectoryName(WearableComponent.Item.Prefab.FilePath)}/{textureName}");
186 if (_picker?.Info !=
null)
252 if (index.X > -1 && index.Y > -1)
259 if (wearableTypes !=
null && wearableTypes.Length > 0)
261 foreach (var value
in wearableTypes)
263 if (Enum.TryParse(value, ignoreCase:
true, out
WearableType wearableType))
288 private readonly
LimbType[] limbType;
289 private readonly
Limb[] limb;
291 private readonly List<DamageModifier> damageModifiers;
294 public readonly Dictionary<StatTypes, float>
WearableStatValues =
new Dictionary<StatTypes, float>();
298 get {
return damageModifiers; }
304 [
Serialize(
false,
IsPropertySaveable.No, description:
"Can the item be used (assuming it has components that are usable in some way) when worn.")]
312 get {
return variant; }
315 if (variant == value) {
return; }
320 item.CreateServerEvent(
this);
325 if (character !=
null)
330 for (
int i = 0; i < wearableSprites.Length; i++)
332 var subElement = wearableElements[i];
334 wearableSprites[i]?.Sprite?.Remove();
338 if (character !=
null)
357 damageModifiers =
new List<DamageModifier>();
360 int spriteCount = element.
Elements().Count(x => x.Name.ToString().ToLowerInvariant() ==
"sprite");
362 variant = Rand.Range(1,
Variants + 1, Rand.RandSync.ServerAndClient);
365 limbType =
new LimbType[spriteCount];
366 limb =
new Limb[spriteCount];
370 foreach (var subElement
in element.
Elements())
372 switch (subElement.Name.ToString().ToLowerInvariant())
375 if (subElement.GetAttribute(
"texture") ==
null)
377 DebugConsole.ThrowError(
"Item \"" +
item.
Name +
"\" doesn't have a texture specified!",
383 subElement.GetAttributeString(
"limb",
"Head"),
true);
385 wearableSprites[i] =
new WearableSprite(subElement,
this, variant);
386 wearableElements[i] = subElement;
388 foreach (var lightElement
in subElement.Elements())
390 if (!lightElement.Name.ToString().Equals(
"lightcomponent", StringComparison.OrdinalIgnoreCase)) {
continue; }
395 foreach (var light
in wearableSprites[i].LightComponents)
403 case "damagemodifier":
406 case "skillmodifier":
407 Identifier skillIdentifier = subElement.GetAttributeIdentifier(
"skillidentifier", Identifier.Empty);
408 float skillValue = subElement.GetAttributeFloat(
"skillvalue", 0f);
420 float statValue = subElement.GetAttributeFloat(
"value", 0f);
431 if (subElement.GetAttributeString(
"Target",
string.Empty).ToLowerInvariant().Contains(
"character"))
445 foreach (Enum value
in Enum.GetValues(typeof(
InvSlotType)))
449 if (allowedSlot.HasFlag(slotType) && !character.Inventory.IsInLimbSlot(
item, slotType))
458 for (
int i = 0; i < wearableSprites.Length; i++ )
460 var wearableSprite = wearableSprites[i];
461 if (!wearableSprite.IsInitialized) { wearableSprite.Init(
picker); }
463 wearableSprite.Picker =
picker;
465 Limb equipLimb = character.AnimController.GetLimb(limbType[i]);
466 if (equipLimb ==
null) {
continue; }
473 if (wearableSprite.LightComponent !=
null)
475 foreach (var light
in wearableSprite.LightComponents)
477 light.ParentBody = equipLimb.
body;
487 float depth = wearable?.Sprite?.Depth ?? 0;
488 float nextDepth = nextWearable?.Sprite?.Depth ?? 0;
489 return nextDepth.CompareTo(depth);
493 var wearableComponent = wearable?.WearableComponent;
494 var nextWearableComponent = nextWearable?.WearableComponent;
495 if (wearableComponent ==
null && nextWearableComponent ==
null) {
return 0; }
496 if (wearableComponent ==
null) {
return -1; }
497 if (nextWearableComponent ==
null) {
return 1; }
498 return wearableComponent.AllowedSlots.Contains(
InvSlotType.OuterClothes).CompareTo(nextWearableComponent.AllowedSlots.Contains(
InvSlotType.OuterClothes));
502 equipLimb.UpdateWearableTypesToHide();
505 character.OnWearablesChanged();
512 base.Drop(dropper, setTransform);
520 if (character ==
null || character.
Removed) {
return; }
521 if (
picker ==
null) {
return; }
523 for (
int i = 0; i < wearableSprites.Length; i++)
526 if (equipLimb ==
null) {
continue; }
530 foreach (var light
in wearableSprites[i].LightComponents)
532 light.ParentBody =
null;
536 equipLimb.
WearingItems.RemoveAll(w => w !=
null && w == wearableSprites[i]);
538 equipLimb.UpdateWearableTypesToHide();
560 if (
item.GetComponent<
Holdable>() is not { IsActive: true })
573 base.RemoveComponentSpecific();
583 public override XElement
Save(XElement parentElement)
585 XElement componentElement = base.Save(parentElement);
586 componentElement.Add(
new XAttribute(
"variant", variant));
587 return componentElement;
590 private int loadedVariant = -1;
593 base.Load(componentElement, usePrefabValues, idRemap, isItemSwap);
600 if (loadedVariant > 0 && loadedVariant <
Variants + 1)
608 base.ServerEventWrite(msg, c, extraData);
614 base.ClientEventRead(msg, sendingTime);
static StatTypes ParseStatType(string statTypeString, string debugIdentifier)
override Vector2? SimPosition
readonly AnimController AnimController
void OnWearablesChanged()
string ReplaceVars(string str)
CharacterInfoPrefab CharacterInfoPrefab
static CharacterPrefab HumanPrefab
static ContentPath FromRaw(string? rawValue)
static readonly ContentPath Empty
string? GetAttributeString(string key, string? def)
Identifier[] GetAttributeIdentifierArray(Identifier[] def, params string[] keys)
Point GetAttributePoint(string key, in Point def)
float GetAttributeFloat(string key, float def)
ContentPackage? ContentPackage
IEnumerable< ContentXElement > Elements()
bool DoesAttributeReferenceFileNameAlone(string key)
ContentPath? GetAttributeContentPath(string key)
bool GetAttributeBool(string key, bool def)
int GetAttributeInt(string key, int def)
string?[] GetAttributeStringArray(string key, string[]? def, bool convertToLowerInvariant=false)
XAttribute? GetAttribute(string name)
void ApplyStatusEffects(ActionType type, float deltaTime, Character character=null, Limb limb=null, Entity useTarget=null, bool isNetworkEvent=false, Vector2? worldPosition=null)
Executes all StatusEffects of the specified type. Note that condition checks are ignored here: that s...
void SetTransform(Vector2 simPosition, float rotation, bool findNewHull=true, bool setPrevTransform=true)
void AddComponent(ItemComponent component)
override string Name
Note that this is not a LocalizedString instance, just the current name of the item as a string....
List< InvSlotType > allowedSlots
bool DisplayContainedStatus
override XElement Save(XElement parentElement)
override void Equip(Character character)
override void ClientEventRead(IReadMessage msg, float sendingTime)
readonly Dictionary< StatTypes, float > WearableStatValues
override void OnItemLoaded()
Called when all the components of the item have been loaded. Use to initialize connections between co...
Wearable(Item item, ContentXElement element)
override void RemoveComponentSpecific()
override void Drop(Character dropper, bool setTransform=true)
a Character has dropped the item
IEnumerable< DamageModifier > DamageModifiers
override void ServerEventWrite(IWriteMessage msg, Client c, NetEntityEvent.IData extraData=null)
readonly Dictionary< Identifier, float > SkillModifiers
readonly float PressureProtection
How deep down does the item protect from pressure? Determined by status effects.
override void Unequip(Character character)
override void Load(ContentXElement componentElement, bool usePrefabValues, IdRemap idRemap, bool isItemSwap)
override void Update(float deltaTime, Camera cam)
override void UpdateBroken(float deltaTime, Camera cam)
readonly List< WearableSprite > WearingItems
Limb GetLimb(LimbType limbType, bool excludeSevered=true, bool excludeLimbsWithSecondaryType=false, bool useSecondaryType=false)
Note that if there are multiple limbs of the same type, only the first (valid) limb is returned.
bool ParseTexturePath(string path="", string file="")
ImmutableHashSet< Identifier > CanBeHiddenByItem
Tags or identifiers of items that can hide this one.
void ParsePath(bool parseSpritePath)
ContentPath UnassignedSpritePath
bool InheritScale
Does the wearable inherit all the scalings of the wearer? Also the wearable's own scale is used!
ObscuringMode ObscureOtherWearables
List< LightComponent > LightComponents
Character Picker
None = Any/Not Defined -> no effect. Changing the gender forces re-initialization,...
WearableSprite(ContentXElement subElement, Wearable wearable, int variant=0)
Note: this constructor cannot initialize automatically, because the gender is unknown at this point....
List< WearableType > HideWearablesOfType
bool AlphaClipOtherWearables
ContentXElement SourceElement
Wearable WearableComponent
bool CanBeHiddenByOtherWearables
WearableSprite(ContentXElement subElement, WearableType type)
void Init(Character picker=null)
Interface for entities that the server can send events to the clients
ActionType
ActionTypes define when a StatusEffect is executed.
StatTypes
StatTypes are used to alter several traits of a character. They are mostly used by talents.