Advertisement
Guest User

Untitled

a guest
May 24th, 2019
103
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 88.30 KB | None | 0 0
  1. using ConsoleLib.Console;
  2. using Lat = XRL.World.Capabilities.Laterality;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. using System;
  6. using XRL.Language;
  7. using XRL.UI;
  8. using XRL.World.Parts;
  9.  
  10. namespace XRL.World
  11. {
  12.  
  13.     [Serializable]
  14.     public class BodyPart
  15.     {
  16.  
  17.         public string Type = null;
  18.         public string VariantType = null;
  19.         public string Description = null;
  20.         public string Name = null;
  21.         public string SupportsDependent = null;
  22.         public string DependsOn = null;
  23.         public string RequiresType = null;
  24.         public string PreventRegenerationBecause = null;
  25.         public int Category = BodyPartCategory.ANIMAL;
  26.         public int Laterality = Lat.NONE;
  27.         public int RequiresLaterality = Lat.ANY;
  28.         public int Mobility = 0;
  29.         public bool Primary = false;
  30.         public bool Native = false;
  31.         public bool Integral = false;
  32.         public bool Mortal = false;
  33.         public bool Abstract = false;
  34.         public bool Extrinsic = false;
  35.         public bool Plural = false;
  36.  
  37.         public Body ParentBody = null;
  38.         public GameObject DefaultBehavior = null;
  39.         public int Position = -1;
  40.  
  41.         public static int IDPreloadSequence = -1;
  42.  
  43.         public int _ID = 0;
  44.         public int ID
  45.         {
  46.             get
  47.             {
  48.                 if (_ID == 0)
  49.                 {
  50.                     if (XRL.Core.XRLCore.Core.Game != null)
  51.                     {
  52.                         _ID = XRL.Core.XRLCore.Core.Game.GetIntGameState("nextId", 1);
  53.                         XRL.Core.XRLCore.Core.Game.SetIntGameState("nextId", _ID + 1);
  54.                     }
  55.                     else
  56.                     {
  57.                         _ID = IDPreloadSequence--;
  58.                     }
  59.                 }
  60.                 return _ID;
  61.             }
  62.             set
  63.             {
  64.                 _ID = value;
  65.             }
  66.         }
  67.  
  68.         public bool idMatch(int testID)
  69.         {
  70.             return _ID == testID;
  71.         }
  72.  
  73.         public bool HasID()
  74.         {
  75.             return _ID != 0;
  76.         }
  77.  
  78.         private BodyPart()
  79.         {
  80.         }
  81.        
  82.         public BodyPart(Body _ParentBody) : this()
  83.         {
  84.             ParentBody = _ParentBody;
  85.         }
  86.  
  87.         public BodyPart(BodyPartType Base, Body _ParentBody) : this(_ParentBody)
  88.         {
  89.             Base.ApplyTo(this);
  90.         }
  91.  
  92.         public BodyPart(string Base, Body _ParentBody) : this(BodyPartType.Require(Base), _ParentBody)
  93.         {
  94.         }
  95.  
  96.         public BodyPart(string Base, int _Laterality, Body _ParentBody) : this(Base, _ParentBody)
  97.         {
  98.             ChangeLaterality(_Laterality);
  99.         }
  100.  
  101.         public BodyPart(string _Type, string _Description, string _Name, Body _ParentBody) : this(_ParentBody)
  102.         {
  103.             Type = _Type;
  104.             Description = (_Description == null) ? Type : _Description;
  105.             Name = (_Name == null) ? Description.ToLower() : _Name;
  106.         }
  107.  
  108.         public BodyPart(BodyPartType Base, int _Laterality, Body _ParentBody, string _DefaultBehavior = null, string _SupportsDependent = null, string _DependsOn = null, string _RequiresType = null, int? _Category = null, int? _RequiresLaterality = null, int? _Mobility = null, bool? _Mortal = null, bool? _Integral = null, bool? _Abstract = null, bool? _Extrinsic = null, bool? _Plural = null) : this(Base, _ParentBody)
  109.         {
  110.             ChangeLaterality(_Laterality);
  111.             if (_DefaultBehavior != null) DefaultBehavior = GameObjectFactory.Factory.CreateObject(_DefaultBehavior, -9999);
  112.             if (_SupportsDependent != null) SupportsDependent = _SupportsDependent;
  113.             if (_DependsOn != null) DependsOn = _DependsOn;
  114.             if (_RequiresType != null) RequiresType = _RequiresType;
  115.             if (_Category != null) Category = (int) _Category;
  116.             if (_RequiresLaterality != null) RequiresLaterality = (int) _RequiresLaterality;
  117.             if (_Mobility != null) Mobility = (int) _Mobility;
  118.             if (_Integral != null) Integral = (bool) _Integral;
  119.             if (_Mortal != null) Mortal = (bool) _Mortal;
  120.             if (_Abstract != null) Abstract = (bool) _Abstract;
  121.             if (_Extrinsic != null) Extrinsic = (bool) _Extrinsic;
  122.             if (_Plural != null) Plural = (bool) _Plural;
  123.         }
  124.  
  125.         public BodyPart(string Base, int _Laterality, Body _ParentBody, string _DefaultBehavior = null, string _SupportsDependent = null, string _DependsOn = null, string _RequiresType = null, int? _Category = null, int? _RequiresLaterality = null, int? _Mobility = null, bool? _Mortal = null, bool? _Integral = null, bool? _Abstract = null, bool? _Extrinsic = null, bool? _Plural = null) : this(Base, _Laterality, _ParentBody)
  126.         {
  127.             if (_DefaultBehavior != null) DefaultBehavior = GameObjectFactory.Factory.CreateObject(_DefaultBehavior, -9999);
  128.             if (_SupportsDependent != null) SupportsDependent = _SupportsDependent;
  129.             if (_DependsOn != null) DependsOn = _DependsOn;
  130.             if (_RequiresType != null) RequiresType = _RequiresType;
  131.             if (_Category != null) Category = (int) _Category;
  132.             if (_RequiresLaterality != null) RequiresLaterality = (int) _RequiresLaterality;
  133.             if (_Mobility != null) Mobility = (int) _Mobility;
  134.             if (_Integral != null) Integral = (bool) _Integral;
  135.             if (_Mortal != null) Mortal = (bool) _Mortal;
  136.             if (_Abstract != null) Abstract = (bool) _Abstract;
  137.             if (_Extrinsic != null) Extrinsic = (bool) _Extrinsic;
  138.             if (_Plural != null) Plural = (bool) _Plural;
  139.         }
  140.  
  141.         public GameObject _Cybernetics = null;
  142.         public GameObject Cybernetics
  143.         {
  144.             get
  145.             {
  146.                 return _Cybernetics;
  147.             }
  148.         }
  149.  
  150.         public GameObject _Equipped = null;
  151.         public GameObject Equipped
  152.         {
  153.             get
  154.             {
  155.                 return _Equipped;
  156.             }
  157.         }
  158.         public List<BodyPart> Parts = new List<BodyPart>(13);
  159.  
  160.         public BodyPartType TypeModel()
  161.         {
  162.             return BodyPartType.Require(Type);
  163.         }
  164.  
  165.         public BodyPartType VariantTypeModel()
  166.         {
  167.             return BodyPartType.Require(VariantType ?? Type);
  168.         }
  169.  
  170.         public BodyPart ChangeLaterality(int NewLaterality)
  171.         {
  172.             Laterality = NewLaterality;
  173.             BodyPartType UseType = VariantTypeModel();
  174.             Description = Lat.WithLateralityAdjective(UseType.Description, Laterality, Capitalized: true);
  175.             Name = Lat.WithLateralityAdjective(UseType.Name, Laterality, Capitalized: false);
  176.             RequiresLaterality = UseType.RequiresLateralityFor(Laterality);
  177.             return this;
  178.         }
  179.  
  180.         public bool IsLateralityConsistent(BodyPartType UseType = null)
  181.         {
  182.             if (UseType == null) UseType = VariantTypeModel();
  183.             if (Description != Lat.WithLateralityAdjective(UseType.Description, Laterality, Capitalized: true)) return false;
  184.             if (Name != Lat.WithLateralityAdjective(UseType.Name, Laterality, Capitalized: false)) return false;
  185.             if (RequiresLaterality != UseType.RequiresLateralityFor(Laterality)) return false;
  186.             return true;
  187.         }
  188.  
  189.         public bool IsLateralitySafeToChange(int ExpectLaterality = Lat.NONE, Body BackupParentBody = null, BodyPart ChildPart = null)
  190.         {
  191.             if (Laterality != ExpectLaterality) return false;
  192.             BodyPartType UseType = VariantTypeModel();
  193.             if (!IsLateralityConsistent(UseType)) return false;
  194.             if (ChildPart != null)
  195.             {
  196.                 if (!IsParentPartOf(ChildPart, BackupParentBody, EvenIfDismembered: true)) return false;
  197.                 if (!ChildPart.IsLateralitySafeToChange(ExpectLaterality, BackupParentBody)) return false;
  198.             }
  199.             return true;
  200.         }
  201.  
  202.         public BodyPart GetParentPart()
  203.         {
  204.             return ParentBody.FindParentPartOf(this);
  205.         }
  206.  
  207.         public BodyPart FindParentPartOf(BodyPart FindPart)
  208.         {
  209.             if (Parts != null)
  210.             {
  211.                 if (Parts.Contains(FindPart)) return this;
  212.                 foreach (BodyPart Part in Parts)
  213.                 {
  214.                     BodyPart FoundPart = Part.FindParentPartOf(FindPart);
  215.                     if (FoundPart != null) return FoundPart;
  216.                 }
  217.             }
  218.             return null;
  219.         }
  220.  
  221.         public bool IsParentPartOf(BodyPart FindPart)
  222.         {
  223.             return Parts != null && Parts.Contains(FindPart);
  224.         }
  225.  
  226.         public bool IsParentPartOf(BodyPart FindPart, Body BackupParentBody, bool EvenIfDismembered)
  227.         {
  228.             if (IsParentPartOf(FindPart)) return true;
  229.             Body UseParentBody = (ParentBody != null) ? ParentBody : BackupParentBody;
  230.             if (UseParentBody != null && UseParentBody.ValidateDismemberedParentPart(this, FindPart)) return true;
  231.             return false;
  232.         }
  233.  
  234.         public bool IsAncestorPartOf(BodyPart FindPart)
  235.         {
  236.             if (Parts != null)
  237.             {
  238.                 if (Parts.Contains(FindPart)) return true;
  239.                 foreach (BodyPart Part in Parts) if (Part.IsAncestorPartOf(FindPart)) return true;
  240.             }
  241.             return false;
  242.         }
  243.  
  244.         public BodyPart FindEquippedItem(GameObject GO)
  245.         {
  246.             if (Equipped == GO) return this;
  247.             foreach (BodyPart Part in Parts)
  248.             {
  249.                 BodyPart FoundPart = Part.FindEquippedItem(GO);
  250.                 if (FoundPart != null) return FoundPart;
  251.             }
  252.             return null;
  253.         }
  254.  
  255.         public BodyPart FindEquippedItem(string Blueprint)
  256.         {
  257.             if (Equipped != null && Equipped.Blueprint == Blueprint) return this;
  258.             foreach (BodyPart Part in Parts)
  259.             {
  260.                 BodyPart FoundPart = Part.FindEquippedItem(Blueprint);
  261.                 if (FoundPart != null) return FoundPart;
  262.             }
  263.             return null;
  264.         }
  265.  
  266.         public bool HasEquippedItem(GameObject GO)
  267.         {
  268.             if (Equipped == GO) return true;
  269.             foreach (BodyPart Part in Parts) if (Part.HasEquippedItem(GO)) return true;
  270.             return false;
  271.         }
  272.  
  273.         public bool HasEquippedItem(string Blueprint)
  274.         {
  275.             if (Equipped != null && Equipped.Blueprint == Blueprint) return true;
  276.             foreach (BodyPart Part in Parts) if (Part.HasEquippedItem(Blueprint)) return true;
  277.             return false;
  278.         }
  279.  
  280.         public bool IsItemEquippedOnLimbType(GameObject GO, string FindType)
  281.         {
  282.             if (Equipped == GO && Type == FindType) return true;
  283.             foreach (BodyPart Part in Parts) if (Part.IsItemEquippedOnLimbType(GO, FindType)) return true;
  284.             return false;
  285.         }
  286.  
  287.         public BodyPart FindCybernetics(GameObject GO)
  288.         {
  289.             if (Cybernetics == GO) return this;
  290.             foreach (BodyPart Part in Parts)
  291.             {
  292.                 BodyPart FoundPart = Part.FindCybernetics(GO);
  293.                 if (FoundPart != null) return FoundPart;
  294.             }
  295.             return null;
  296.         }
  297.  
  298.         public bool IsItemImplantedInLimbType(GameObject GO, string FindType)
  299.         {
  300.             if (Cybernetics == GO && Type == FindType) return true;
  301.             foreach (BodyPart Part in Parts) if (Part.IsItemImplantedInLimbType(GO, FindType)) return true;
  302.             return false;
  303.         }
  304.  
  305.         public GameObject Unimplant(bool MoveToInventory = true)
  306.         {
  307.             GameObject obj = _Cybernetics;
  308.             if (obj != null)
  309.             {
  310.                 obj.FireEvent(Event.New("Unimplanted", "Object", ParentBody.ParentObject, "BodyPart", this));
  311.  
  312.                 if (_Equipped == obj)
  313.                 {
  314.                     _Equipped = null;
  315.                 }
  316.  
  317.                 if (MoveToInventory)
  318.                 {
  319.                     Inventory pInventory = ParentBody.ParentObject.GetPart<Inventory>();
  320.                     if (pInventory != null) pInventory.AddObject(obj);
  321.                 }
  322.  
  323.                 _Cybernetics = null;
  324.             }
  325.             return obj;
  326.         }
  327.  
  328.         public GameObject Dismember()
  329.         {
  330.             if (ParentBody == null) return null;
  331.             return ParentBody.Dismember(this);
  332.         }
  333.  
  334.         public void Implant(GameObject Cybernetic)
  335.         {
  336.             if (_Cybernetics != null) Unimplant();
  337.  
  338.             _Cybernetics = Cybernetic;
  339.  
  340.             if (Cybernetic.HasTag("CyberneticsUsesEqSlot"))
  341.             {
  342.                 if( _Equipped != null ) TryUnequip();
  343.                 Equip(Cybernetic, true);
  344.             }
  345.  
  346.             _Cybernetics.FireEvent(Event.New("Implanted", "Object", ParentBody.ParentObject, "BodyPart", this));
  347.         }
  348.  
  349.         public bool Equip(GameObject Item, bool bSilent = false)
  350.         {
  351.             Event eCommandEquipObject = Event.New("CommandEquipObject");
  352.             eCommandEquipObject.bSilent = bSilent;
  353.             eCommandEquipObject.AddParameter("Object", Item);
  354.             eCommandEquipObject.AddParameter("BodyPart", this);
  355.             return ParentBody.ParentObject.FireEvent(eCommandEquipObject);
  356.         }
  357.  
  358.         public bool DoEquip(GameObject GO, bool bSilent = false)
  359.         {
  360.             if (ParentBody == null) throw new Exception("cannot equip without parent body");
  361.             ParentBody.WeightCache = -1;
  362.             string SlotsSpec = GO.pPhysics.UsesSlots;
  363.             if (!string.IsNullOrEmpty(SlotsSpec))
  364.             {
  365.                 List<string> SlotList = new List<string>(SlotsSpec.Split(','));
  366.                 SlotList.Remove(this.Type);
  367.                 foreach (string Slot in SlotList)
  368.                 {
  369.                     int nHave = ParentBody.GetUnequippedPartCountExcept(Slot, this);
  370.                     int nNeed = 0;
  371.                     foreach (string CountSlot in SlotList) if (CountSlot == Slot) nNeed++;
  372.                     if (nNeed > nHave)
  373.                     {
  374.                         if (!bSilent && ParentBody.ParentObject.IsPlayer())
  375.                         {
  376.                             if (nNeed == nHave + 1)
  377.                             {
  378.                                 Popup.Show("You need another free " + Slot + " to equip that!");
  379.                             }
  380.                             else
  381.                             {
  382.                                 Popup.Show("You need another " + Grammar.Cardinal(nNeed - nHave) + " free " + Grammar.Pluralize(Slot) + " to equip that!");
  383.                             }
  384.                         }
  385.                         return false;
  386.                     }
  387.                 }
  388.  
  389.                 foreach (string Slot in SlotList)
  390.                 {
  391.                     foreach (BodyPart P in ParentBody.GetPart(Slot))
  392.                     {
  393.                         if (P != this && P.Equipped == null)
  394.                         {
  395.                             P._Equipped = GO;
  396.                             GO.pPhysics.Equipped = ParentBody.ParentObject;
  397.                             break;
  398.                         }
  399.                     }
  400.                 }
  401.             }
  402.             else
  403.             if (GO.pPhysics.bUsesTwoSlots && (ParentBody.ParentObject.GetIntProperty("HugeHands", 0) <= 0 || !GO.FireEvent("AllowHugeHands")))
  404.             {
  405.                 List<BodyPart> OtherSlots = ParentBody.GetPart(Type);
  406.                 if (OtherSlots.CleanContains(this)) OtherSlots.Remove(this);
  407.                 List<BodyPart> FreeSlots = new List<BodyPart>(4);
  408.  
  409.                 foreach (BodyPart P in OtherSlots)
  410.                 {
  411.                     if (P.Equipped == null) FreeSlots.Add(P);
  412.                 }
  413.  
  414.                 if (ParentBody.IsPlayer())
  415.                 {
  416.                     if (FreeSlots.Count > 0)
  417.                     {
  418.                         FreeSlots[0]._Equipped = GO;
  419.                     }
  420.                     else
  421.                     {
  422.                         if (!bSilent && ParentBody.ParentObject.IsPlayer())
  423.                         {
  424.                             Popup.Show("You need another free " + Type + " to equip that!");
  425.                         }
  426.                         return false;
  427.                     }
  428.                 }
  429.                 else
  430.                 {
  431.                     if (FreeSlots.Count > 0)
  432.                     {
  433.                         if (ParentBody != null) ParentBody.WeightCache = -1;
  434.                         FreeSlots[0]._Equipped = GO;
  435.                     }
  436.                     else
  437.                     if (FreeSlots.Count == 0)
  438.                     {
  439.                         return false;
  440.                     }
  441.                 }
  442.             }
  443.  
  444.             if (ParentBody != null) ParentBody.WeightCache = -1;
  445.             _Equipped = GO;
  446.  
  447.             return true;
  448.         }
  449.  
  450.         private void ClearEquipped()
  451.         {
  452.             if (ParentBody != null) ParentBody.WeightCache = -1;
  453.             _Equipped = null;
  454.         }
  455.  
  456.         public bool TryUnequip(bool Silent = false, bool SemiForced = false)
  457.         {
  458.             Event E = Event.New("CommandUnequipObject", "BodyPart", this);
  459.             if (SemiForced) E.SetParameter("SemiForced", 1);
  460.             if (Silent) E.SetSilent(true);
  461.             return ParentBody.ParentObject.FireEvent(E);
  462.         }
  463.  
  464.         public bool ForceUnequip(bool Silent = false)
  465.         {
  466.             Event E = Event.New("CommandForceUnequipObject", "BodyPart", this);
  467.             if (Silent) E.SetSilent(true);
  468.             return ParentBody.ParentObject.FireEvent(E);
  469.         }
  470.  
  471.         public void Unequip()
  472.         {
  473.             if (Equipped == null) return;
  474.             foreach (BodyPart Part in (ParentBody == null) ? GetParts() : ParentBody.GetParts())
  475.             {
  476.                 if (Part != this && Part.Equipped == Equipped)
  477.                 {
  478.                     Part.ClearEquipped();
  479.                 }
  480.             }
  481.             ClearEquipped();
  482.         }
  483.  
  484.         public BodyPart DeepCopy(GameObject Parent, Body NewBody)
  485.         {
  486.             BodyPart Copy = new BodyPart();
  487.             Copy.Type = Type;
  488.             Copy.VariantType = VariantType;
  489.             Copy.Description = Description;
  490.             Copy.Name = Name;
  491.             Copy.SupportsDependent = SupportsDependent;
  492.             Copy.DependsOn = DependsOn;
  493.             Copy.RequiresType = RequiresType;
  494.             Copy.PreventRegenerationBecause = PreventRegenerationBecause;
  495.             Copy.Category = Category;
  496.             Copy.Laterality = Laterality;
  497.             Copy.RequiresLaterality = RequiresLaterality;
  498.             Copy.Mobility = Mobility;
  499.             Copy.Primary = Primary;
  500.             Copy.Native = Native;
  501.             Copy.Integral = Integral;
  502.             Copy.Mortal = Mortal;
  503.             Copy.Abstract = Abstract;
  504.             Copy.Extrinsic = Extrinsic;
  505.             Copy.Plural = Plural;
  506.             Copy.Position = Position;
  507.             Copy._ID = _ID;
  508.             Copy.ParentBody = NewBody;
  509.  
  510.             if (DefaultBehavior != null)
  511.             {
  512.                 GameObject oCopy = DefaultBehavior.DeepCopy();
  513.                 Parent.DeepCopyInventoryObjectMap.Add(DefaultBehavior, oCopy);
  514.                 oCopy.pPhysics._Equipped = Parent;
  515.                 Copy.DefaultBehavior = oCopy;
  516.             }
  517.  
  518.             if (Equipped != null)
  519.             {
  520.                 if( !Parent.DeepCopyInventoryObjectMap.ContainsKey( Equipped ) )
  521.                 {
  522.                     GameObject oCopy = Equipped.DeepCopy();
  523.                     Parent.DeepCopyInventoryObjectMap.Add(Equipped, oCopy);
  524.                     Body.DeepCopyEquipMap.Add(oCopy, Copy);
  525.                     //Physics pPhysics = oCopy.GetPart("Physics") as Physics;
  526.                     //pPhysics._Equipped = Parent;
  527.                 }
  528.             }
  529.  
  530.             foreach (BodyPart Part in Parts)
  531.             {
  532.                 if (!Part.Extrinsic)
  533.                 {
  534.                     Copy.AddPart(Part.DeepCopy(Parent, NewBody));
  535.                 }
  536.             }
  537.  
  538.             return Copy;
  539.         }
  540.  
  541.         public void Save(SerializationWriter Writer)
  542.         {
  543.             Writer.Write(Type);
  544.             Writer.Write(VariantType);
  545.             Writer.Write(Description);
  546.             Writer.Write(Name);
  547.             Writer.Write(SupportsDependent);
  548.             Writer.Write(DependsOn);
  549.             Writer.Write(RequiresType);
  550.             Writer.Write(PreventRegenerationBecause);
  551.             Writer.Write(Category);
  552.             Writer.Write(Laterality);
  553.             Writer.Write(RequiresLaterality);
  554.             Writer.Write(Mobility);
  555.             Writer.Write(Primary);
  556.             Writer.Write(Native);
  557.             Writer.Write(Integral);
  558.             Writer.Write(Mortal);
  559.             Writer.Write(Abstract);
  560.             Writer.Write(Extrinsic);
  561.             Writer.Write(Plural);
  562.             Writer.Write(Position);
  563.             Writer.Write(_ID);
  564.             Writer.WriteGameObject(DefaultBehavior);
  565.             Writer.WriteGameObject(_Equipped);
  566.             Writer.WriteGameObject(_Cybernetics);
  567.  
  568.             if (Parts == null)
  569.             {
  570.                 Writer.Write(-1);
  571.             }
  572.             else
  573.             {
  574.                 Writer.Write(Parts.Count);
  575.                 foreach (BodyPart Part in Parts) Part.Save(Writer);
  576.             }
  577.         }
  578.  
  579.         public static BodyPart Load(SerializationReader Reader, Body ParentBody)
  580.         {
  581.             BodyPart NewPart = new BodyPart();
  582.  
  583.             NewPart.Type = Reader.ReadString();
  584.             NewPart.VariantType = Reader.ReadString();
  585.             NewPart.Description = Reader.ReadString();
  586.             NewPart.Name = Reader.ReadString();
  587.             NewPart.SupportsDependent = Reader.ReadString();
  588.             NewPart.DependsOn = Reader.ReadString();
  589.             NewPart.RequiresType = Reader.ReadString();
  590.             NewPart.PreventRegenerationBecause = Reader.ReadString();
  591.             NewPart.Category = Reader.ReadInt32();
  592.             NewPart.Laterality = Reader.ReadInt32();
  593.             NewPart.RequiresLaterality = Reader.ReadInt32();
  594.             NewPart.Mobility = Reader.ReadInt32();
  595.             NewPart.Primary = Reader.ReadBoolean();
  596.             NewPart.Native = Reader.ReadBoolean();
  597.             NewPart.Integral = Reader.ReadBoolean();
  598.             NewPart.Mortal = Reader.ReadBoolean();
  599.             NewPart.Abstract = Reader.ReadBoolean();
  600.             NewPart.Extrinsic = Reader.ReadBoolean();
  601.             NewPart.Plural = Reader.ReadBoolean();
  602.             NewPart.Position = Reader.ReadInt32();
  603.             NewPart._ID = Reader.ReadInt32();
  604.             NewPart.DefaultBehavior = Reader.ReadGameObject();
  605.             NewPart._Equipped = Reader.ReadGameObject();
  606.             NewPart._Cybernetics = Reader.ReadGameObject();
  607.             NewPart.ParentBody = ParentBody;
  608.  
  609.             int nCount = Reader.ReadInt32();
  610.             if (nCount == -1) NewPart.Parts = null;
  611.             for (int x = 0; x < nCount; x++)
  612.             {
  613.                 NewPart.Parts.Add(Load(Reader,ParentBody));
  614.             }
  615.  
  616.             return NewPart;
  617.         }
  618.  
  619.         public int GetWeight()
  620.         {
  621.             int Return = 0;
  622.             if (Equipped != null && Equipped.pPhysics != null && IsFirstSlotForEquipped())
  623.             {
  624.                 Cybernetics2BaseItem Implant = Equipped.GetPart<Cybernetics2BaseItem>();
  625.                 if (Implant != null)
  626.                 {
  627.                     if (Implant.ImplantedOn == null) Return += Equipped.pPhysics.Weight;
  628.                 }
  629.                 else
  630.                 {
  631.                     Return += Equipped.pPhysics.Weight;
  632.                 }
  633.             }
  634.             if (Parts != null)
  635.             {
  636.                 foreach (BodyPart Part in Parts)
  637.                 {
  638.                     if (Part != null) Return += Part.GetWeight();
  639.                 }
  640.             }
  641.             return Return;
  642.         }
  643.  
  644.         public void Clear()
  645.         {
  646.             DefaultBehavior = null;
  647.             ClearEquipped();
  648.  
  649.             if (Parts != null)
  650.             {
  651.                 for( int x=0;x<Parts.Count;x++ )
  652.                 {
  653.                     BodyPart Part = Parts[x];
  654.                     if( Part != null ) Part.Clear();
  655.                 }
  656.             }
  657.             Parts = null;
  658.         }
  659.  
  660.         public void StripAllEquipment(List<GameObject> Return)
  661.         {
  662.             if (Equipped != null)
  663.             {
  664.                 Return.Add(Equipped);
  665.                 Equipped.FireEvent("Unequipped");
  666.                 Unequip();
  667.             }
  668.  
  669.             if (Parts != null)
  670.             {
  671.                 foreach (BodyPart Part in Parts)
  672.                 {
  673.                     Part.StripAllEquipment(Return);
  674.                 }
  675.             }
  676.         }
  677.  
  678.         public void GetPrimaryHandEquippedObjects(List<GameObject> Return)
  679.         {
  680.             if (Primary && Type == "Hand" && Equipped != null) Return.Add(Equipped);
  681.  
  682.             if (Parts != null)
  683.             {
  684.                 for (int x = 0; x < Parts.Count; x++)
  685.                 {
  686.                     BodyPart Part = Parts[x];
  687.                     if (Part != null) Part.GetPrimaryHandEquippedObjects(Return);
  688.                 }
  689.             }
  690.         }
  691.  
  692.         public void GetPrimaryEquippedObjects(List<GameObject> Return)
  693.         {
  694.             if (Primary && Equipped != null) Return.Add(Equipped);
  695.             if (Primary && DefaultBehavior != null && Equipped == null ) Return.Add(DefaultBehavior);
  696.  
  697.             if (Parts != null)
  698.             {
  699.                 for( int x=0;x<Parts.Count;x++ )
  700.                 {
  701.                     BodyPart Part = Parts[x];
  702.                     if( Part != null ) Part.GetPrimaryEquippedObjects(Return);
  703.                 }
  704.             }
  705.         }
  706.  
  707.         public int GetEquippedObjectCount()
  708.         {
  709.             int Count = 0;
  710.             if (Equipped != null && IsFirstSlotForEquipped()) Count++;
  711.             if (Parts != null)
  712.             {
  713.                 foreach (BodyPart Part in Parts) if (Part != null) Count += Part.GetEquippedObjectCount();
  714.             }
  715.             return Count;
  716.         }
  717.  
  718.         public int GetEquippedObjectCount(Predicate<GameObject> pFilter)
  719.         {
  720.             int Count = 0;
  721.             if (Equipped != null && pFilter(Equipped) && IsFirstSlotForEquipped()) Count++;
  722.             if (Parts != null)
  723.             {
  724.                 foreach (BodyPart Part in Parts) if (Part != null) Count += Part.GetEquippedObjectCount(pFilter);
  725.             }
  726.             return Count;
  727.         }
  728.  
  729.         public void GetEquippedObjects(List<GameObject> Return)
  730.         {
  731.             if (Equipped != null && !Return.Contains(Equipped)) Return.Add(Equipped);
  732.             if (Parts != null)
  733.             {
  734.                 foreach (BodyPart Part in Parts)
  735.                 {
  736.                     if (Part != null) Part.GetEquippedObjects(Return);
  737.                 }
  738.             }
  739.         }
  740.  
  741.         public void GetEquippedObjects(List<GameObject> Return, Predicate<GameObject> pFilter)
  742.         {
  743.             if (Equipped != null && !Return.Contains(Equipped) && pFilter(Equipped)) Return.Add(Equipped);
  744.             if (Parts != null)
  745.             {
  746.                 foreach (BodyPart Part in Parts)
  747.                 {
  748.                     if (Part != null) Part.GetEquippedObjects(Return, pFilter);
  749.                 }
  750.             }
  751.         }
  752.  
  753.         public void ForeachEquippedObject(Action<GameObject> aProc)
  754.         {
  755.             if (Equipped != null && IsFirstSlotForEquipped()) aProc(Equipped);
  756.             if (Parts != null)
  757.             {
  758.                 for (int i = 0, j = Parts.Count; i < j; i++)
  759.                 {
  760.                     BodyPart Part = Parts[i];
  761.                     if (Part != null) Part.ForeachEquippedObject(aProc);
  762.                     if (Parts.Count < j)
  763.                     {
  764.                         int diff = j - Parts.Count;
  765.                         i -= diff;
  766.                         j -= diff;
  767.                     }
  768.                 }
  769.             }
  770.         }
  771.  
  772.         public int GetInstalledCyberneticsCount()
  773.         {
  774.             int Count = 0;
  775.             if (Cybernetics != null && ParentBody.FindCybernetics(Cybernetics) == this) Count++;
  776.             if (Parts != null)
  777.             {
  778.                 foreach (BodyPart Part in Parts) if (Part != null) Count += Part.GetInstalledCyberneticsCount();
  779.             }
  780.             return Count;
  781.         }
  782.  
  783.         public int GetInstalledCyberneticsCount(Predicate<GameObject> pFilter)
  784.         {
  785.             int Count = 0;
  786.             if (Cybernetics != null && pFilter(Cybernetics) && ParentBody.FindCybernetics(Cybernetics) == this) Count++;
  787.             if (Parts != null)
  788.             {
  789.                 foreach (BodyPart Part in Parts) if (Part != null) Count += Part.GetInstalledCyberneticsCount(pFilter);
  790.             }
  791.             return Count;
  792.         }
  793.  
  794.         public void GetInstalledCybernetics(List<GameObject> Return)
  795.         {
  796.             if (Cybernetics != null && !Return.Contains(Cybernetics)) Return.Add(Cybernetics);
  797.             if (Parts != null)
  798.             {
  799.                 foreach (BodyPart Part in Parts)
  800.                 {
  801.                     if (Part != null) Part.GetInstalledCybernetics(Return);
  802.                 }
  803.             }
  804.         }
  805.  
  806.         public void GetInstalledCybernetics(List<GameObject> Return, Predicate<GameObject> pFilter)
  807.         {
  808.             if (Cybernetics != null && !Return.Contains(Cybernetics) && pFilter(Cybernetics)) Return.Add(Cybernetics);
  809.             if (Parts != null)
  810.             {
  811.                 foreach (BodyPart Part in Parts)
  812.                 {
  813.                     if (Part != null) Part.GetInstalledCybernetics(Return, pFilter);
  814.                 }
  815.             }
  816.         }
  817.  
  818.         public bool AnyInstalledCybernetics()
  819.         {
  820.             if (Cybernetics != null) return true;
  821.             if (Parts != null)
  822.             {
  823.                 foreach (BodyPart Part in Parts) if (Part != null && Part.AnyInstalledCybernetics()) return true;
  824.             }
  825.             return false;
  826.         }
  827.  
  828.         public bool AnyInstalledCybernetics(Predicate<GameObject> pFilter)
  829.         {
  830.             if (Cybernetics != null && pFilter(Cybernetics)) return true;
  831.             if (Parts != null)
  832.             {
  833.                 foreach (BodyPart Part in Parts) if (Part != null && Part.AnyInstalledCybernetics(pFilter)) return true;
  834.             }
  835.             return false;
  836.         }
  837.  
  838.         public void ForeachInstalledCybernetics(Action<GameObject> aProc)
  839.         {
  840.             if (Cybernetics != null && ParentBody.FindCybernetics(Cybernetics) == this) aProc(Cybernetics);
  841.             if (Parts != null)
  842.             {
  843.                 for (int i = 0, j = Parts.Count; i < j; i++)
  844.                 {
  845.                     BodyPart Part = Parts[i];
  846.                     if (Part != null) Part.ForeachInstalledCybernetics(aProc);
  847.                     if (Parts.Count < j)
  848.                     {
  849.                         int diff = j - Parts.Count;
  850.                         i -= diff;
  851.                         j -= diff;
  852.                     }
  853.                 }
  854.             }
  855.         }
  856.  
  857.         public bool Render( RenderEvent E )
  858.         {
  859.             if( Equipped != null ) Equipped.Render( E );
  860.             for( int x = 0;x<Parts.Count;x++ )
  861.             {
  862.                 Parts[x].Render( E );
  863.             }
  864.             return true;
  865.         }
  866.  
  867.         public bool BeforeRender( Event E )
  868.         {
  869.             if( Equipped != null ) Equipped.BeforeRender( E );
  870.             if (Cybernetics != null) Cybernetics.BeforeRender(E);
  871.  
  872.             if (Parts != null)
  873.             {
  874.                 for (int x = 0; x < Parts.Count; x++)
  875.                 {
  876.                     if (Parts[x] != null) Parts[x].BeforeRender(E);
  877.                 }
  878.             }
  879.             return true;
  880.         }
  881.  
  882.         public virtual bool AnyRegisteredEvent(string ID)
  883.         {
  884.             if (ID == "QuerySlotList") return true;
  885.             if (Equipped != null && Equipped.HasRegisteredEvent(ID)) return true;
  886.             if (Cybernetics != null && Cybernetics.HasRegisteredEvent(ID)) return true;
  887.             if (DefaultBehavior != null && DefaultBehavior.HasRegisteredEvent(ID)) return true;
  888.             if (Parts != null)
  889.             {
  890.                 foreach (BodyPart Part in Parts)
  891.                 {
  892.                     if (ID != "BeforeRenderWhileEquipped" || ID != "BeforeRenderLateWhileEquipped" || Part.Type != "Thrown Weapon")
  893.                     {
  894.                         if (Part.AnyRegisteredEvent(ID)) return true;
  895.                     }
  896.                 }
  897.             }
  898.             return false;
  899.         }
  900.  
  901.         public virtual bool FireEvent(Event E)
  902.         {
  903.  
  904.             if (E.ID == "QuerySlotList")
  905.             {
  906.                 if (Equipped != null && !Equipped.FireEvent("CanBeUnequipped"))
  907.                 {
  908.                 }
  909.                 else
  910.                 if (Cybernetics != null && Cybernetics.HasTag("CyberneticsUsesEqSlot") && !Cybernetics.FireEvent("CanBeUnequipped"))
  911.                 {
  912.                 }
  913.                 else
  914.                 {
  915.                     GameObject GO = E.GetGameObjectParameter("Object");
  916.                     List<BodyPart> List = E.GetParameter("SlotList") as List<BodyPart>;
  917.  
  918.                     List<GameObject> Return = new List<GameObject>(1);
  919.                     Event eQueryEquippableList = Event.New("QueryEquippableList");
  920.                     eQueryEquippableList.AddParameter("EquippingObject", GO);
  921.                     eQueryEquippableList.AddParameter("SlotType", Type);
  922.                     eQueryEquippableList.AddParameter("EquippableList", Return);
  923.                     GO.FireEvent(eQueryEquippableList);
  924.                     if (Return.Count > 0) List.Add(this);
  925.                 }
  926.  
  927.                 if (Parts != null) foreach (BodyPart p in Parts) if (!p.FireEvent(E)) return false;
  928.  
  929.                 return true;
  930.             }
  931.  
  932.             bool bSuccess = true;
  933.             if (Equipped != null && IsFirstSlotForEquipped())
  934.             {
  935.                 if (!Equipped.FireEvent(E)) bSuccess = false;
  936.                 if (E.ID == "EndTurn" && Equipped != null) Equipped.CleanEffects();
  937.             }
  938.             if (!bSuccess) return false;
  939.  
  940.             if (Cybernetics != null && ParentBody.FindCybernetics(Cybernetics) == this)
  941.             {
  942.                 if (!Cybernetics.FireEvent(E)) bSuccess = false;
  943.                 if (E.ID == "EndTurn" && Cybernetics != null) Cybernetics.CleanEffects();
  944.             }
  945.             if (!bSuccess) return false;
  946.  
  947.             if (DefaultBehavior != null)
  948.             {
  949.                 if (!DefaultBehavior.FireEvent(E)) bSuccess = false;
  950.                 if (E.ID == "EndTurn") DefaultBehavior.CleanEffects();
  951.             }
  952.             if (!bSuccess) return false;
  953.  
  954.             if (Parts != null)
  955.             {
  956.                 foreach (BodyPart Part in Parts)
  957.                 {
  958.                     if (E.ID != "BeforeRenderWhileEquipped" || Part.Type != "Thrown Weapon")
  959.                     {
  960.                         if (!Part.FireEvent(E)) bSuccess = false;
  961.                     }
  962.                 }
  963.                 if (!bSuccess) return false;
  964.             }
  965.  
  966.             return bSuccess;
  967.         }
  968.  
  969.         public override string ToString()
  970.         {
  971.             StringBuilder SB = new StringBuilder();
  972.  
  973.             SB.Append(Name + ": &C");
  974.             if (Equipped == null && DefaultBehavior == null)
  975.             {
  976.                 SB.Append("&K-&y");
  977.             }
  978.             else
  979.             if (Equipped == null)
  980.             {
  981.                 SB.Append("&K" + DefaultBehavior.ShortDisplayName);
  982.             }
  983.             else
  984.             {
  985.                 SB.Append(Equipped.ShortDisplayName);
  986.             }
  987.             if (Primary) SB.Append(" &G*Primary&y");
  988.  
  989.             return SB.ToString();
  990.         }
  991.  
  992.         public void UnequipPartAndChildren(bool Silent = false, Cell Where = null)
  993.         {
  994.             if (Equipped != null && !Equipped.IsNatural())
  995.             {
  996.                 if (ParentBody != null)
  997.                 {
  998.                     GameObject HeldObject = Equipped;
  999.                     try
  1000.                     {
  1001.                         Event eCommandForceUnequipObject = Event.New("CommandForceUnequipObject", "BodyPart", this, "NoTake", 1);
  1002.                         if (Silent) eCommandForceUnequipObject.SetSilent(true);
  1003.                         ParentBody.ParentObject.FireEvent(eCommandForceUnequipObject);
  1004.                     }
  1005.                     catch (Exception ex)
  1006.                     {
  1007.                         MetricsManager.LogException("UnequipPartAndChildren unequip", ex);
  1008.                     }
  1009.  
  1010.                     try
  1011.                     {
  1012.                         if (Where == null) Where = ParentBody.ParentObject.GetDropCell();
  1013.                         if (Where == null)
  1014.                         {
  1015.                             HeldObject.RemoveFromContext();
  1016.                             HeldObject.Obliterate();
  1017.                         }
  1018.                         else
  1019.                         {
  1020.                             if (ParentBody.ParentObject.FireEvent(Event.New("CommandDropObject", "Object", HeldObject, "Forced", 1, "Where", Where)))
  1021.                             {
  1022.                                 if (!Silent && HeldObject.CurrentCell == Where && HeldObject.IsVisible())
  1023.                                 {
  1024.                                     if (HeldObject.HasProperName) Messages.MessageQueue.AddPlayerMessage(HeldObject.The + HeldObject.DisplayName + " &y" + HeldObject.GetVerb("fall", false) + " to the ground.");
  1025.                                     else if (ParentBody.ParentObject.IsPlayer()) Messages.MessageQueue.AddPlayerMessage("Your " + HeldObject.DisplayName + " &y" + HeldObject.GetVerb("fall", false) + " to the ground.");
  1026.                                     else Messages.MessageQueue.AddPlayerMessage(Grammar.MakePossessive(ParentBody.ParentObject.The + ParentBody.ParentObject.DisplayName) + " " + HeldObject.DisplayName + " &y" + HeldObject.GetVerb("fall", false) + " to the ground.");
  1027.                                 }
  1028.                             }
  1029.                         }
  1030.                     }
  1031.                     catch (Exception ex)
  1032.                     {
  1033.                         MetricsManager.LogException("UnequipPartAndChildren drop", ex);
  1034.                     }
  1035.                 }
  1036.             }
  1037.             else
  1038.             {
  1039.                 if( Equipped != null && ParentBody.ParentObject != null )
  1040.                 {
  1041.                     Equipped.FireEvent(Event.New("Unequipped", "UnequippingObject", ParentBody.ParentObject));
  1042.                 }
  1043.                 Unequip();
  1044.             }
  1045.             if (Parts != null) foreach (BodyPart P in Parts) P.UnequipPartAndChildren(Silent);
  1046.         }
  1047.  
  1048.         public void ToString(StringBuilder SB)
  1049.         {
  1050.             SB.Append(ToString());
  1051.             SB.Append("\n");
  1052.             if (Parts != null)
  1053.             {
  1054.                 foreach (BodyPart p in Parts)
  1055.                 {
  1056.                     p.ToString(SB);
  1057.                 }
  1058.             }
  1059.         }
  1060.  
  1061.         public bool RemovePart(BodyPart Part, bool DoUpdate = true)
  1062.         {
  1063.             if (Parts == null) return false;
  1064.             if (Parts.Contains(Part))
  1065.             {
  1066.                 Part.UnequipPartAndChildren();
  1067.                 Parts.Remove(Part);
  1068.                 if (DoUpdate && ParentBody != null)
  1069.                 {
  1070.                     ParentBody.UpdateBodyParts();
  1071.                     ParentBody.RecalculateTypeArmor(Part.Type);
  1072.                 }
  1073.                 return true;
  1074.             }
  1075.             else
  1076.             {
  1077.                 foreach (BodyPart subPart in Parts)
  1078.                 {
  1079.                     if (subPart.RemovePart(Part, DoUpdate)) return true;
  1080.                 }
  1081.                 return false;
  1082.             }
  1083.         }
  1084.  
  1085.         public bool RemovePartByID(int removeID, bool DoUpdate = true)
  1086.         {
  1087.             BodyPart Part = GetPartByID(removeID);
  1088.             if (Part == null) return false;
  1089.             return RemovePart(Part, DoUpdate);
  1090.         }
  1091.  
  1092.         private bool PositionOccupied(int Position, BodyPart ExceptPart = null)
  1093.         {
  1094.             if (Parts != null) foreach (BodyPart Part in Parts) if (Part.Position == Position && Part != ExceptPart) return true;
  1095.             if (ParentBody != null && ParentBody.DismemberedPartHasPosition(this, Position, ExceptPart)) return true;
  1096.             return false;
  1097.         }
  1098.  
  1099.         private void AssignPosition(BodyPart Part, int Position)
  1100.         {
  1101.             if (PositionOccupied(Position, ExceptPart: Part))
  1102.             {
  1103.                 foreach (BodyPart OtherPart in Parts)
  1104.                 {
  1105.                     if (OtherPart.Position >= Position) OtherPart.Position++;
  1106.                 }
  1107.                 if (ParentBody != null) ParentBody.CheckDismemberedPartRenumberingOnPositionAssignment(this, Position, Part);
  1108.             }
  1109.             Part.Position = Position;
  1110.         }
  1111.  
  1112.         private int NextPosition(BodyPart ExceptPart = null)
  1113.         {
  1114.             int Result = (ParentBody != null) ? ParentBody.GetLastDismemberedPartPosition(this, ExceptPart) : -1;
  1115.             if (Parts != null) foreach (BodyPart Part in Parts) if (Part.Position > Result && Part != ExceptPart) Result = Part.Position;
  1116.             return Result + 1;
  1117.         }
  1118.  
  1119.         private int FindIndexForPosition(int Position)
  1120.         {
  1121.             if (Parts != null) for (int i = 0; i < Parts.Count; i++) if (Parts[i].Position >= Position) return i;
  1122.             return -1;
  1123.         }
  1124.  
  1125.         public BodyPart AddPart(BodyPart NewPart, int Position = -1, bool DoUpdate = true)
  1126.         {
  1127.             if (Parts == null) return null;
  1128.             if (Parts.IndexOf(NewPart) != -1) throw new Exception("part for add already attached");
  1129.             if (Position == -1)
  1130.             {
  1131.                 Position = NextPosition(NewPart);
  1132.             }
  1133.             else
  1134.             {
  1135.                 while (Position > 0 && !PositionOccupied(Position - 1, ExceptPart: NewPart))
  1136.                 {
  1137.                     Position--;
  1138.                 }
  1139.             }
  1140.             int Index = FindIndexForPosition(Position);
  1141.             if (Index == -1)
  1142.             {
  1143.                 Parts.Add(NewPart);
  1144.             }
  1145.             else
  1146.             {
  1147.                 Parts.Insert(Index, NewPart);
  1148.             }
  1149.             AssignPosition(NewPart, Position);
  1150.             if (ParentBody != null)
  1151.             {
  1152.                 NewPart.ParentBody = ParentBody;
  1153.                 if (DoUpdate)
  1154.                 {
  1155.                     ParentBody.UpdateBodyParts();
  1156.                     ParentBody.RecalculateTypeArmor(NewPart.Type);
  1157.                 }
  1158.             }
  1159.             return NewPart;
  1160.         }
  1161.  
  1162.         public BodyPart AddPart(BodyPart NewPart, string InsertAfter)
  1163.         {
  1164.             int Position = LastPartTypePosition(InsertAfter);
  1165.             if (Position != -1) Position++;
  1166.             return AddPart(NewPart, Position);
  1167.         }
  1168.  
  1169.         public BodyPart AddPart(BodyPart NewPart, string InsertAfter, string OrInsertBefore)
  1170.         {
  1171.             if (OrInsertBefore == null) return AddPart(NewPart, InsertAfter);
  1172.             int Position = LastPartTypePosition(InsertAfter);
  1173.             if (Position == -1)
  1174.             {
  1175.                 Position = FirstPartTypePosition(OrInsertBefore);
  1176.             }
  1177.             else
  1178.             {
  1179.                 Position++;
  1180.             }
  1181.             return AddPart(NewPart, Position);
  1182.         }
  1183.  
  1184.         public BodyPart AddPart(BodyPart NewPart, string InsertAfter, string[] OrInsertBefore)
  1185.         {
  1186.             if (OrInsertBefore == null) return AddPart(NewPart, InsertAfter);
  1187.             int Position = LastPartTypePosition(InsertAfter);
  1188.             if (Position == -1)
  1189.             {
  1190.                 foreach (string Type in OrInsertBefore)
  1191.                 {
  1192.                     Position = FirstPartTypePosition(Type);
  1193.                     if (Position != -1) break;
  1194.                 }
  1195.             }
  1196.             else
  1197.             {
  1198.                 Position++;
  1199.             }
  1200.             return AddPart(NewPart, Position);
  1201.         }
  1202.  
  1203.         public BodyPart AddPart(BodyPartType Base, int Laterality = Lat.NONE, string DefaultBehavior = null, string SupportsDependent = null, string DependsOn = null, string RequiresType = null, int? Category = null, int? RequiresLaterality = null, int? Mobility = null, bool? Integral = null, bool? Mortal = null, bool? Abstract = null, bool? Extrinsic = null, bool? Plural = null)
  1204.         {
  1205.             return AddPart(new BodyPart(Base, Laterality, ParentBody, DefaultBehavior, SupportsDependent, DependsOn, RequiresType, Category, RequiresLaterality, Mobility, Integral, Mortal, Abstract, Extrinsic, Plural));
  1206.         }
  1207.  
  1208.         public BodyPart AddPart(string Base, int Laterality = Lat.NONE, string DefaultBehavior = null, string SupportsDependent = null, string DependsOn = null, string RequiresType = null, int? Category = null, int? RequiresLaterality = null, int? Mobility = null, bool? Integral = null, bool? Mortal = null, bool? Abstract = null, bool? Extrinsic = null, bool? Plural = null)
  1209.         {
  1210.             return AddPart(new BodyPart(Base, Laterality, ParentBody, DefaultBehavior, SupportsDependent, DependsOn, RequiresType, Category, RequiresLaterality, Mobility, Integral, Mortal, Abstract, Extrinsic, Plural));
  1211.         }
  1212.  
  1213.         public BodyPart AddPartAt(BodyPartType Base, int Laterality = Lat.NONE, string DefaultBehavior = null, string SupportsDependent = null, string DependsOn = null, string RequiresType = null, int? Category = null, int? RequiresLaterality = null, int? Mobility = null, bool? Integral = null, bool? Mortal = null, bool? Abstract = null, bool? Extrinsic = null, bool? Plural = null, string InsertAfter = null, string OrInsertBefore = null)
  1214.         {
  1215.             return AddPart(new BodyPart(Base, Laterality, ParentBody, DefaultBehavior, SupportsDependent, DependsOn, RequiresType, Category, RequiresLaterality, Mobility, Integral, Mortal, Abstract, Extrinsic, Plural), InsertAfter, OrInsertBefore);
  1216.         }
  1217.  
  1218.         public BodyPart AddPartAt(string Base, int Laterality = Lat.NONE, string DefaultBehavior = null, string SupportsDependent = null, string DependsOn = null, string RequiresType = null, int? Category = null, int? RequiresLaterality = null, int? Mobility = null, bool? Integral = null, bool? Mortal = null, bool? Abstract = null, bool? Extrinsic = null, bool? Plural = null, string InsertAfter = null, string OrInsertBefore = null)
  1219.         {
  1220.             return AddPart(new BodyPart(Base, Laterality, ParentBody, DefaultBehavior, SupportsDependent, DependsOn, RequiresType, Category, RequiresLaterality, Mobility, Integral, Mortal, Abstract, Extrinsic, Plural), InsertAfter, OrInsertBefore);
  1221.         }
  1222.  
  1223.         public BodyPart AddPartAt(BodyPartType Base, int Laterality = Lat.NONE, string DefaultBehavior = null, string SupportsDependent = null, string DependsOn = null, string RequiresType = null, int? Category = null, int? RequiresLaterality = null, int? Mobility = null, bool? Integral = null, bool? Mortal = null, bool? Abstract = null, bool? Extrinsic = null, bool? Plural = null, string InsertAfter = null, string[] OrInsertBefore = null)
  1224.         {
  1225.             return AddPart(new BodyPart(Base, Laterality, ParentBody, DefaultBehavior, SupportsDependent, DependsOn, RequiresType, Category, RequiresLaterality, Mobility, Integral, Mortal, Abstract, Extrinsic, Plural), InsertAfter, OrInsertBefore);
  1226.         }
  1227.  
  1228.         public BodyPart AddPartAt(string Base, int Laterality = Lat.NONE, string DefaultBehavior = null, string SupportsDependent = null, string DependsOn = null, string RequiresType = null, int? Category = null, int? RequiresLaterality = null, int? Mobility = null, bool? Integral = null, bool? Mortal = null, bool? Abstract = null, bool? Extrinsic = null, bool? Plural = null, string InsertAfter = null, string[] OrInsertBefore = null)
  1229.         {
  1230.             return AddPart(new BodyPart(Base, Laterality, ParentBody, DefaultBehavior, SupportsDependent, DependsOn, RequiresType, Category, RequiresLaterality, Mobility, Integral, Mortal, Abstract, Extrinsic, Plural), InsertAfter, OrInsertBefore);
  1231.         }
  1232.  
  1233.         public BodyPart AddPartAt(BodyPart InsertAfter, BodyPartType Base, int Laterality = Lat.NONE, string DefaultBehavior = null, string SupportsDependent = null, string DependsOn = null, string RequiresType = null, int? Category = null, int? RequiresLaterality = null, int? Mobility = null, bool? Integral = null, bool? Mortal = null, bool? Abstract = null, bool? Extrinsic = null, bool? Plural = null)
  1234.         {
  1235.             return AddPart(new BodyPart(Base, Laterality, ParentBody, DefaultBehavior, SupportsDependent, DependsOn, RequiresType, Category, RequiresLaterality, Mobility, Integral, Mortal, Abstract, Extrinsic, Plural), InsertAfter.Position + 1);
  1236.         }
  1237.  
  1238.         public BodyPart AddPartAt(BodyPart InsertAfter, string Base, int Laterality = Lat.NONE, string DefaultBehavior = null, string SupportsDependent = null, string DependsOn = null, string RequiresType = null, int? Category = null, int? RequiresLaterality = null, int? Mobility = null, bool? Integral = null, bool? Mortal = null, bool? Abstract = null, bool? Extrinsic = null, bool? Plural = null)
  1239.         {
  1240.             return AddPart(new BodyPart(Base, Laterality, ParentBody, DefaultBehavior, SupportsDependent, DependsOn, RequiresType, Category, RequiresLaterality, Mobility, Integral, Mortal, Abstract, Extrinsic, Plural), InsertAfter.Position + 1);
  1241.         }
  1242.  
  1243.         public int FirstPartTypePosition(string Type, BodyPart ExceptPart = null)
  1244.         {
  1245.             int Result = -1;
  1246.             if (Parts != null)
  1247.             {
  1248.                 foreach (BodyPart Part in Parts)
  1249.                 {
  1250.                     if (Part.Type == Type && Part != ExceptPart)
  1251.                     {
  1252.                         Result = Part.Position;
  1253.                         break;
  1254.                     }
  1255.                 }
  1256.             }
  1257.             if (ParentBody != null)
  1258.             {
  1259.                 int DismemberedPosition = ParentBody.GetFirstDismemberedPartTypePosition(this, Type, ExceptPart);
  1260.                 if (DismemberedPosition != -1 && (Result == -1 || DismemberedPosition < Result)) Result = DismemberedPosition;
  1261.             }
  1262.             return Result;
  1263.         }
  1264.  
  1265.         public int LastPartTypePosition(string Type, BodyPart ExceptPart = null)
  1266.         {
  1267.             int Result = -1;
  1268.             if (Parts != null)
  1269.             {
  1270.                 for (int i = Parts.Count - 1; i >= 0; i--)
  1271.                 {
  1272.                     if (Parts[i].Type == Type && Parts[i] != ExceptPart)
  1273.                     {
  1274.                        Result = Parts[i].Position;
  1275.                        break;
  1276.                     }
  1277.                 }
  1278.             }
  1279.             if (ParentBody != null)
  1280.             {
  1281.                 int DismemberedPosition = ParentBody.GetLastDismemberedPartTypePosition(this, Type, ExceptPart);
  1282.                 if (DismemberedPosition > Result) Result = DismemberedPosition;
  1283.             }
  1284.             return Result;
  1285.         }
  1286.  
  1287.         public BodyPart GetPart(Predicate<BodyPart> pFilter)
  1288.         {
  1289.             if (pFilter(this)) return this;
  1290.             if (Parts != null)
  1291.             {
  1292.                 foreach (BodyPart Part in Parts)
  1293.                 {
  1294.                     if (Part != null)
  1295.                     {
  1296.                         BodyPart Find = Part.GetPart(pFilter);
  1297.                         if (Find != null) return Find;
  1298.                     }
  1299.                 }
  1300.             }
  1301.             return null;
  1302.         }
  1303.  
  1304.         public bool AnyPart(Predicate<BodyPart> pFilter)
  1305.         {
  1306.             if (pFilter(this)) return true;
  1307.             if (Parts != null)
  1308.             {
  1309.                 foreach (BodyPart Part in Parts)
  1310.                 {
  1311.                     if (Part != null && Part.AnyPart(pFilter)) return true;
  1312.                 }
  1313.             }
  1314.             return false;
  1315.         }
  1316.  
  1317.         public void ForeachPart(Action<BodyPart> aProc)
  1318.         {
  1319.             try
  1320.             {
  1321.                 aProc(this);
  1322.                 for (int i = 0, j = Parts.Count; i < j; i++)
  1323.                 {
  1324.                     BodyPart Part = Parts[i];
  1325.                     if( Part != null )
  1326.                     {
  1327.                         Part.ForeachPart( aProc );
  1328.                     }
  1329.                     if (Parts.Count < j)
  1330.                     {
  1331.                         int diff = j - Parts.Count;
  1332.                         i -= diff;
  1333.                         j -= diff;
  1334.                     }
  1335.                 }
  1336.             }
  1337.             catch
  1338.             {
  1339.                 UnityEngine.Debug.LogWarning("Collection was modified during ForeachPart");
  1340.             }
  1341.         }
  1342.  
  1343.         public bool ForeachPart(Predicate<BodyPart> pProc)
  1344.         {
  1345.             try
  1346.             {
  1347.                 if( !pProc(this)) return false;
  1348.                 for (int i = 0, j = Parts.Count; i < j; i++)
  1349.                 {
  1350.                     BodyPart Part = Parts[i];
  1351.                     if (Part != null)
  1352.                     {
  1353.                         if (!Part.ForeachPart(pProc)) return false;
  1354.                     }
  1355.                     if (Parts.Count < j)
  1356.                     {
  1357.                         int diff = j - Parts.Count;
  1358.                         i -= diff;
  1359.                         j -= diff;
  1360.                     }
  1361.                 }
  1362.             }
  1363.             catch
  1364.             {
  1365.                 UnityEngine.Debug.LogWarning("Collection was modified during ForeachPart");
  1366.             }
  1367.  
  1368.             return true;
  1369.         }
  1370.  
  1371.         public int GetPartCount()
  1372.         {
  1373.             int Result = 1;
  1374.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null) Result += p.GetPartCount();
  1375.             return Result;
  1376.         }
  1377.  
  1378.         public int GetPartCount(string RequiredType)
  1379.         {
  1380.             int Result = 0;
  1381.             if (Type == RequiredType) Result++;
  1382.             if (Parts != null)
  1383.             {
  1384.                 foreach (BodyPart p in Parts)
  1385.                 {
  1386.                     Result += p.GetPartCount(RequiredType);
  1387.                 }
  1388.             }
  1389.             return Result;
  1390.         }
  1391.  
  1392.         public int GetPartCount(Predicate<BodyPart> pFilter)
  1393.         {
  1394.             int Result = 0;
  1395.             if (pFilter(this)) Result++;
  1396.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null) Result += p.GetPartCount(pFilter);
  1397.             return Result;
  1398.         }
  1399.  
  1400.         public int GetPartNameCount(string FindName)
  1401.         {
  1402.             int Result = 0;
  1403.             if (Name == FindName) Result++;
  1404.             if (Parts != null)
  1405.             {
  1406.                 foreach (BodyPart p in Parts)
  1407.                 {
  1408.                     Result += p.GetPartNameCount(FindName);
  1409.                 }
  1410.             }
  1411.             return Result;
  1412.         }
  1413.  
  1414.         public int GetPartDescriptionCount(string FindDescription)
  1415.         {
  1416.             int Result = 0;
  1417.             if (Description == FindDescription) Result++;
  1418.             if (Parts != null)
  1419.             {
  1420.                 foreach (BodyPart p in Parts)
  1421.                 {
  1422.                     Result += p.GetPartDescriptionCount(FindDescription);
  1423.                 }
  1424.             }
  1425.             return Result;
  1426.         }
  1427.  
  1428.         public bool AnyCategoryParts(int FindCategory)
  1429.         {
  1430.             if (FindCategory == Category) return true;
  1431.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null && p.AnyCategoryParts(FindCategory)) return true;
  1432.             return false;
  1433.         }
  1434.  
  1435.         public int GetCategoryPartCount(int FindCategory)
  1436.         {
  1437.             int Result = (FindCategory == Category) ? 1 : 0;
  1438.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null) Result += p.GetCategoryPartCount(FindCategory);
  1439.             return Result;
  1440.         }
  1441.  
  1442.         public int GetCategoryPartCount(int FindCategory, string FindType)
  1443.         {
  1444.             int Result = 0;
  1445.             if (FindCategory == Category && FindType == Type) Result++;
  1446.             if (Parts != null)
  1447.             {
  1448.                 foreach (BodyPart p in Parts)
  1449.                 {
  1450.                     Result += p.GetCategoryPartCount(FindCategory, FindType);
  1451.                 }
  1452.             }
  1453.             return Result;
  1454.         }
  1455.  
  1456.         public int GetCategoryPartCount(int FindCategory, Predicate<BodyPart> pFilter)
  1457.         {
  1458.             int Result = 0;
  1459.             if (FindCategory == Category && pFilter(this)) Result++;
  1460.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null) Result += p.GetCategoryPartCount(FindCategory, pFilter);
  1461.             return Result;
  1462.         }
  1463.  
  1464.         public int GetNativePartCount()
  1465.         {
  1466.             int Result = Native ? 1 : 0;
  1467.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null) Result += p.GetNativePartCount();
  1468.             return Result;
  1469.         }
  1470.  
  1471.         public int GetNativePartCount(string RequiredType)
  1472.         {
  1473.             int Result = 0;
  1474.             if (Type == RequiredType && Native) Result++;
  1475.             if (Parts != null)
  1476.             {
  1477.                 foreach (BodyPart p in Parts)
  1478.                 {
  1479.                     Result += p.GetNativePartCount(RequiredType);
  1480.                 }
  1481.             }
  1482.             return Result;
  1483.         }
  1484.  
  1485.         public int GetNativePartCount(Predicate<BodyPart> pFilter)
  1486.         {
  1487.             int Result = 0;
  1488.             if (Native && pFilter(this)) Result++;
  1489.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null) Result += p.GetNativePartCount(pFilter);
  1490.             return Result;
  1491.         }
  1492.  
  1493.         public int GetAddedPartCount()
  1494.         {
  1495.             int Result = Native ? 0 : 1;
  1496.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null) Result += p.GetAddedPartCount();
  1497.             return Result;
  1498.         }
  1499.  
  1500.         public int GetAddedPartCount(string RequiredType)
  1501.         {
  1502.             int Result = 0;
  1503.             if (Type == RequiredType && !Native) Result++;
  1504.             if (Parts != null)
  1505.             {
  1506.                 foreach (BodyPart p in Parts)
  1507.                 {
  1508.                     Result += p.GetAddedPartCount(RequiredType);
  1509.                 }
  1510.             }
  1511.             return Result;
  1512.         }
  1513.  
  1514.         public int GetAddedPartCount(Predicate<BodyPart> pFilter)
  1515.         {
  1516.             int Result = 0;
  1517.             if (!Native && pFilter(this)) Result++;
  1518.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null) Result += p.GetAddedPartCount(pFilter);
  1519.             return Result;
  1520.         }
  1521.  
  1522.         public int GetMortalPartCount()
  1523.         {
  1524.             int Result = Mortal ? 1 : 0;
  1525.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null) Result += p.GetMortalPartCount();
  1526.             return Result;
  1527.         }
  1528.  
  1529.         public int GetMortalPartCount(string RequiredType)
  1530.         {
  1531.             int Result = 0;
  1532.             if (Type == RequiredType && Mortal) Result++;
  1533.             if (Parts != null)
  1534.             {
  1535.                 foreach (BodyPart p in Parts)
  1536.                 {
  1537.                     Result += p.GetMortalPartCount(RequiredType);
  1538.                 }
  1539.             }
  1540.             return Result;
  1541.         }
  1542.  
  1543.         public int GetMortalPartCount(Predicate<BodyPart> pFilter)
  1544.         {
  1545.             int Result = 0;
  1546.             if (Mortal && pFilter(this)) Result++;
  1547.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null) Result += p.GetMortalPartCount(pFilter);
  1548.             return Result;
  1549.         }
  1550.  
  1551.         public bool AnyMortalParts()
  1552.         {
  1553.             if (Mortal) return true;
  1554.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null && p.AnyMortalParts()) return true;
  1555.             return false;
  1556.         }
  1557.  
  1558.         public bool IsEquippedOnCategory(GameObject FindObj, int FindCategory)
  1559.         {
  1560.             if (FindObj == Equipped && FindCategory == Category) return true;
  1561.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null && p.IsEquippedOnCategory(FindObj, FindCategory)) return true;
  1562.             return false;
  1563.         }
  1564.  
  1565.         public bool IsImplantedInCategory(GameObject FindObj, int FindCategory)
  1566.         {
  1567.             if (FindObj == Cybernetics && FindCategory == Category) return true;
  1568.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null && p.IsImplantedInCategory(FindObj, FindCategory)) return true;
  1569.             return false;
  1570.         }
  1571.  
  1572.         public int GetTotalMobility()
  1573.         {
  1574.             int Result = Mobility;
  1575.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null) Result += p.GetTotalMobility();
  1576.             return Result;
  1577.         }
  1578.  
  1579.         public void MarkAllNative()
  1580.         {
  1581.             Native = true;
  1582.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null) p.MarkAllNative();
  1583.         }
  1584.  
  1585.         public void CategorizeAll(int ApplyCategory)
  1586.         {
  1587.             Category = ApplyCategory;
  1588.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null) p.CategorizeAll(ApplyCategory);
  1589.         }
  1590.  
  1591.         public void CategorizeAllExcept(int ApplyCategory, int SkipCategory)
  1592.         {
  1593.             if (Category != SkipCategory) Category = ApplyCategory;
  1594.             if (Parts != null) foreach (BodyPart p in Parts) if (p != null) p.CategorizeAllExcept(ApplyCategory, SkipCategory);
  1595.         }
  1596.  
  1597.         public List<BodyPart> GetParts()
  1598.         {
  1599.             List<BodyPart> Return = new List<BodyPart>(GetPartCount());
  1600.             Return.Add(this);
  1601.             if (Parts != null) foreach (BodyPart p in Parts) p.GetParts(Return);
  1602.             return Return;
  1603.         }
  1604.  
  1605.         public void GetParts(List<BodyPart> Return)
  1606.         {
  1607.             Return.Add(this);
  1608.             if (Parts != null) foreach (BodyPart p in Parts) p.GetParts(Return);
  1609.         }
  1610.  
  1611.         public void GetPartsEquippedOn(GameObject obj, List<BodyPart> Result)
  1612.         {
  1613.             if (Equipped == obj) Result.Add(this);
  1614.             if (Parts != null) foreach (BodyPart p in Parts) p.GetPartsEquippedOn(obj, Result);
  1615.         }
  1616.  
  1617.         public List<BodyPart> GetPartsEquippedOn(GameObject obj)
  1618.         {
  1619.             List<BodyPart> Result = new List<BodyPart>(GetPartCountEquippedOn(obj));
  1620.             GetPartsEquippedOn(obj, Result);
  1621.             return Result;
  1622.         }
  1623.  
  1624.         public int GetPartCountEquippedOn(GameObject obj)
  1625.         {
  1626.             int Result = 0;
  1627.             if (Equipped == obj) Result++;
  1628.             if (Parts != null) foreach (BodyPart p in Parts) Result += p.GetPartCountEquippedOn(obj);
  1629.             return Result;
  1630.         }
  1631.  
  1632.         public List<BodyPart> GetUnequippedPart(string RequiredType, List<BodyPart> Return)
  1633.         {
  1634.             if (Type == RequiredType && Equipped == null) Return.Add(this);
  1635.             if (Parts != null) foreach (BodyPart p in Parts) p.GetUnequippedPart(RequiredType, Return);
  1636.             return Return;
  1637.         }
  1638.  
  1639.         public int GetUnequippedPartCount(string RequiredType)
  1640.         {
  1641.             int result = 0;
  1642.             if (Type == RequiredType && Equipped == null) result++;
  1643.             if (Parts != null) foreach (BodyPart p in Parts) result += p.GetUnequippedPartCount(RequiredType);
  1644.             return result;
  1645.         }
  1646.  
  1647.         public int GetUnequippedPartCountExcept(string RequiredType, BodyPart ExceptPart)
  1648.         {
  1649.             int result = 0;
  1650.             if (Type == RequiredType && Equipped == null && ExceptPart != this) result++;
  1651.             if (Parts != null) foreach (BodyPart p in Parts) result += p.GetUnequippedPartCountExcept(RequiredType, ExceptPart);
  1652.             return result;
  1653.         }
  1654.  
  1655.         public List<BodyPart> GetPart(string RequiredType, List<BodyPart> Return)
  1656.         {
  1657.             if (Type == RequiredType) Return.Add(this);
  1658.             if (Parts != null) foreach (BodyPart p in Parts) p.GetPart(RequiredType, Return);
  1659.             return Return;
  1660.         }
  1661.  
  1662.         public BodyPart GetFirstPart(string RequiredType)
  1663.         {
  1664.             if (Type == RequiredType) return this;
  1665.             if (Parts != null)
  1666.             {
  1667.                 foreach (BodyPart p in Parts)
  1668.                 {
  1669.                     BodyPart Part = p.GetFirstPart(RequiredType);
  1670.                     if (Part != null) return Part;
  1671.                 }
  1672.             }
  1673.             return null;
  1674.         }
  1675.  
  1676.         public BodyPart GetFirstPart(string RequiredType, int RequiredLaterality)
  1677.         {
  1678.             if (RequiredLaterality == Lat.ANY) return GetFirstPart(RequiredType);
  1679.             if (Type == RequiredType)
  1680.             {
  1681.                 if (RequiredLaterality == Lat.NONE)
  1682.                 {
  1683.                     if (Laterality == Lat.NONE) return this;
  1684.                 }
  1685.                 else
  1686.                 {
  1687.                     if ((Laterality & RequiredLaterality) == RequiredLaterality) return this;
  1688.                 }
  1689.             }
  1690.             if (Parts != null)
  1691.             {
  1692.                 foreach (BodyPart p in Parts)
  1693.                 {
  1694.                     BodyPart Part = p.GetFirstPart(RequiredType, RequiredLaterality);
  1695.                     if (Part != null) return Part;
  1696.                 }
  1697.             }
  1698.             return null;
  1699.         }
  1700.  
  1701.         public BodyPart GetFirstAttachedPart(string RequiredType)
  1702.         {
  1703.             if (Parts != null)
  1704.             {
  1705.                 foreach (BodyPart Part in Parts)
  1706.                 {
  1707.                     if (Part.Type == RequiredType) return Part;
  1708.                 }
  1709.             }
  1710.             return null;
  1711.         }
  1712.  
  1713.         public BodyPart GetFirstAttachedPart(string RequiredType, Body BackupParentBody, bool EvenIfDismembered)
  1714.         {
  1715.             BodyPart Result = GetFirstAttachedPart(RequiredType);
  1716.             if (EvenIfDismembered)
  1717.             {
  1718.                 Body UseParentBody = (ParentBody != null) ? ParentBody : BackupParentBody;
  1719.                 if (UseParentBody != null)
  1720.                 {
  1721.                     BodyPart Dismembered = UseParentBody.GetFirstDismemberedPartByType(this, RequiredType);
  1722.                     if (Dismembered != null && (Result == null || Dismembered.Position < Result.Position)) Result = Dismembered;
  1723.                 }
  1724.             }
  1725.             return Result;
  1726.         }
  1727.  
  1728.         public BodyPart GetFirstAttachedPart(string RequiredType, int RequiredLaterality)
  1729.         {
  1730.             if (RequiredLaterality == Lat.ANY) return GetFirstAttachedPart(RequiredType);
  1731.             if (Parts != null)
  1732.             {
  1733.                 if (RequiredLaterality == Lat.NONE)
  1734.                 {
  1735.                     foreach (BodyPart Part in Parts)
  1736.                     {
  1737.                         if (Part.Type == RequiredType && Part.Laterality == Lat.NONE) return Part;
  1738.                     }
  1739.                 }
  1740.                 else
  1741.                 {
  1742.                     foreach (BodyPart Part in Parts)
  1743.                     {
  1744.                         if (Part.Type == RequiredType && (Part.Laterality & RequiredLaterality) == RequiredLaterality) return Part;
  1745.                     }
  1746.                 }
  1747.             }
  1748.             return null;
  1749.         }
  1750.  
  1751.         public BodyPart GetFirstAttachedPart(string RequiredType, int RequiredLaterality, Body BackupParentBody, bool EvenIfDismembered)
  1752.         {
  1753.             BodyPart Result = GetFirstAttachedPart(RequiredType, RequiredLaterality);
  1754.             if (EvenIfDismembered)
  1755.             {
  1756.                 Body UseParentBody = (ParentBody != null) ? ParentBody : BackupParentBody;
  1757.                 if (UseParentBody != null)
  1758.                 {
  1759.                     BodyPart Dismembered = UseParentBody.GetFirstDismemberedPartByTypeAndLaterality(this, RequiredType, RequiredLaterality);
  1760.                     if (Dismembered != null && (Result == null || Dismembered.Position < Result.Position)) Result = Dismembered;
  1761.                 }
  1762.             }
  1763.             return Result;
  1764.         }
  1765.  
  1766.         public BodyPart GetPartByName(string RequiredPart)
  1767.         {
  1768.             if (Name == RequiredPart) return this;
  1769.             if (Parts != null)
  1770.             {
  1771.                 foreach (BodyPart p in Parts)
  1772.                 {
  1773.                     BodyPart Part = p.GetPartByName(RequiredPart);
  1774.                     if (Part != null) return Part;
  1775.                 }
  1776.             }
  1777.             return null;
  1778.         }
  1779.  
  1780.         public BodyPart GetPartByNameStartsWith(string RequiredPart)
  1781.         {
  1782.             if (Name != null && Name.StartsWith(RequiredPart)) return this;
  1783.             if (Parts != null)
  1784.             {
  1785.                 foreach (BodyPart p in Parts)
  1786.                 {
  1787.                     BodyPart Part = p.GetPartByNameStartsWith(RequiredPart);
  1788.                     if (Part != null) return Part;
  1789.                 }
  1790.             }
  1791.             return null;
  1792.         }
  1793.  
  1794.         public BodyPart GetPartByDescription(string RequiredPart)
  1795.         {
  1796.             if (Description == RequiredPart) return this;
  1797.             if (Parts != null)
  1798.             {
  1799.                 foreach (BodyPart p in Parts)
  1800.                 {
  1801.                     BodyPart Part = p.GetPartByDescription(RequiredPart);
  1802.                     if (Part != null) return Part;
  1803.                 }
  1804.             }
  1805.             return null;
  1806.         }
  1807.  
  1808.         public BodyPart GetPartByDescriptionStartsWith(string RequiredPart)
  1809.         {
  1810.             if (Description != null && Description.StartsWith(RequiredPart)) return this;
  1811.             if (Parts != null)
  1812.             {
  1813.                 foreach (BodyPart p in Parts)
  1814.                 {
  1815.                     BodyPart Part = p.GetPartByDescriptionStartsWith(RequiredPart);
  1816.                     if (Part != null) return Part;
  1817.                 }
  1818.             }
  1819.             return null;
  1820.         }
  1821.  
  1822.         public BodyPart GetPartByID(int findID)
  1823.         {
  1824.             if (idMatch(findID)) return this;
  1825.             if (Parts != null)
  1826.             {
  1827.                 foreach (BodyPart p in Parts)
  1828.                 {
  1829.                     BodyPart Part = p.GetPartByID(findID);
  1830.                     if (Part != null) return Part;
  1831.                 }
  1832.             }
  1833.             return null;
  1834.         }
  1835.  
  1836.         public BodyPart GetPartBySupportsDependent(string findSupportsDependent)
  1837.         {
  1838.             if (SupportsDependent == findSupportsDependent) return this;
  1839.             if (Parts != null)
  1840.             {
  1841.                 foreach (BodyPart p in Parts)
  1842.                 {
  1843.                     BodyPart Part = p.GetPartBySupportsDependent(findSupportsDependent);
  1844.                     if (Part != null) return Part;
  1845.                 }
  1846.             }
  1847.             return null;
  1848.         }
  1849.  
  1850.         protected void GetNamePosition(BodyPart FindPart, ref int Found, ref bool Done)
  1851.         {
  1852.             if (FindPart == this)
  1853.             {
  1854.                 Found++;
  1855.                 Done = true;
  1856.                 return;
  1857.             }
  1858.             if (FindPart.Name == Name) Found++;
  1859.             if (Parts != null)
  1860.             {
  1861.                 foreach (BodyPart Part in Parts)
  1862.                 {
  1863.                     Part.GetNamePosition(FindPart, ref Found, ref Done);
  1864.                     if (Done) break;
  1865.                 }
  1866.             }
  1867.         }
  1868.  
  1869.         public int GetNamePosition()
  1870.         {
  1871.             int Found = 0;
  1872.             bool Done = false;
  1873.             if (ParentBody != null) ParentBody.GetBody().GetNamePosition(this, ref Found, ref Done);
  1874.             else GetNamePosition(this, ref Found, ref Done);
  1875.             return Found;
  1876.         }
  1877.  
  1878.         protected void GetDescriptionPosition(BodyPart FindPart, ref int Found, ref bool Done)
  1879.         {
  1880.             if (FindPart == this)
  1881.             {
  1882.                 Found++;
  1883.                 Done = true;
  1884.                 return;
  1885.             }
  1886.             if (FindPart.Description == Description) Found++;
  1887.             if (Parts != null)
  1888.             {
  1889.                 foreach (BodyPart Part in Parts)
  1890.                 {
  1891.                     Part.GetDescriptionPosition(FindPart, ref Found, ref Done);
  1892.                     if (Done) break;
  1893.                 }
  1894.             }
  1895.         }
  1896.  
  1897.         public int GetDescriptionPosition()
  1898.         {
  1899.             int Found = 0;
  1900.             bool Done = false;
  1901.             if (ParentBody != null) ParentBody.GetBody().GetDescriptionPosition(this, ref Found, ref Done);
  1902.             else GetDescriptionPosition(this, ref Found, ref Done);
  1903.             return Found;
  1904.         }
  1905.  
  1906.         public string GetCardinalName()
  1907.         {
  1908.             int pos = GetNamePosition();
  1909.             if (pos == 1) return Name;
  1910.             return
  1911.                 Event.NewStringBuilder()
  1912.                 .Append(Name)
  1913.                 .Append(" (")
  1914.                 .Append(pos)
  1915.                 .Append(')')
  1916.                 .ToString()
  1917.             ;
  1918.         }
  1919.  
  1920.         public string GetOrdinalName()
  1921.         {
  1922.             if (GetPartNameCount(Name) == 1) return Name;
  1923.             return
  1924.                 Event.NewStringBuilder()
  1925.                 .Append(Grammar.Ordinal(GetNamePosition()))
  1926.                 .Append(' ')
  1927.                 .Append(Name)
  1928.                 .ToString()
  1929.             ;
  1930.         }
  1931.  
  1932.         public string GetCardinalDescription()
  1933.         {
  1934.             StringBuilder SB = Event.NewStringBuilder();
  1935.             if (!Abstract)
  1936.             {
  1937.                 string Color = BodyPartCategory.GetColor(Category);
  1938.                 if (Color != null) SB.Append('&').Append(Color);
  1939.             }
  1940.             SB.Append(Description);
  1941.             int pos = GetDescriptionPosition();
  1942.             if (pos != 1)
  1943.             {
  1944.                 SB
  1945.                     .Append(" (")
  1946.                     .Append(pos)
  1947.                     .Append(')')
  1948.                 ;
  1949.             }
  1950.             return SB.ToString();
  1951.         }
  1952.  
  1953.         public string GetOrdinalDescription()
  1954.         {
  1955.             StringBuilder SB = Event.NewStringBuilder();
  1956.             if (!Abstract)
  1957.             {
  1958.                 string Color = BodyPartCategory.GetColor(Category);
  1959.                 if (Color != null) SB.Append('&').Append(Color);
  1960.             }
  1961.             int num = GetPartDescriptionCount(Description);
  1962.             if (num != 1) return Description;
  1963.             {
  1964.                 int pos = GetDescriptionPosition();
  1965.                 SB
  1966.                     .Append(ColorUtility.CapitalizeExceptFormatting(Grammar.Ordinal(pos)))
  1967.                     .Append(' ')
  1968.                 ;
  1969.             }
  1970.             SB.Append(Description);
  1971.             return SB.ToString();
  1972.         }
  1973.  
  1974.         public bool IsConcretelyDependent()
  1975.         {
  1976.             return DependsOn != null;
  1977.         }
  1978.  
  1979.         public bool IsAbstractlyDependent()
  1980.         {
  1981.             return RequiresType != null;
  1982.         }
  1983.  
  1984.         public bool IsDependent()
  1985.         {
  1986.             return IsConcretelyDependent() || IsAbstractlyDependent();
  1987.         }
  1988.  
  1989.         public bool IsConcretelyUnsupported(Body UseParentBody = null)
  1990.         {
  1991.             if (DependsOn == null) return false;
  1992.             if (UseParentBody != null) return UseParentBody.GetPartBySupportsDependent(DependsOn) == null;
  1993.             else if (ParentBody != null) return ParentBody.GetPartBySupportsDependent(DependsOn) == null;
  1994.             else return GetPartBySupportsDependent(DependsOn) == null;
  1995.         }
  1996.  
  1997.         public bool IsAbstractlyUnsupported(Body UseParentBody = null)
  1998.         {
  1999.             if (RequiresType == null) return false;
  2000.             if (UseParentBody != null) return UseParentBody.GetFirstPart(RequiresType, RequiresLaterality) == null;
  2001.             else if (ParentBody != null) return ParentBody.GetFirstPart(RequiresType, RequiresLaterality) == null;
  2002.             else return GetFirstPart(RequiresType, RequiresLaterality) == null;
  2003.         }
  2004.  
  2005.         public bool IsUnsupported(Body UseParentBody = null)
  2006.         {
  2007.             return IsConcretelyUnsupported(UseParentBody) || IsAbstractlyUnsupported(UseParentBody);
  2008.         }
  2009.  
  2010.         public bool IsSeverable()
  2011.         {
  2012.             if (Abstract) return false;
  2013.             if (Integral) return false;
  2014.             if (IsDependent()) return false;
  2015.             return true;
  2016.         }
  2017.  
  2018.         public bool SeverRequiresDecapitate()
  2019.         {
  2020.             return Mortal;
  2021.         }
  2022.  
  2023.         public bool IsRegenerable()
  2024.         {
  2025.             return IsSeverable() && PreventRegenerationBecause == null;
  2026.         }
  2027.  
  2028.         public bool IsRecoverable(Body UseParentBody = null)
  2029.         {
  2030.             return IsDependent() && !IsUnsupported(UseParentBody);
  2031.         }
  2032.  
  2033.         public void FindUnsupportedParts(ref List<BodyPart> Result)
  2034.         {
  2035.             if (Parts != null) foreach (BodyPart Part in Parts) Part.FindUnsupportedParts(ref Result);
  2036.             if (IsUnsupported())
  2037.             {
  2038.                 if (Result == null)
  2039.                 {
  2040.                     Result = new List<BodyPart>(1){ this };
  2041.                 }
  2042.                 else
  2043.                 {
  2044.                     Result.Add(this);
  2045.                 }
  2046.             }
  2047.         }
  2048.  
  2049.         public List<BodyPart> FindUnsupportedParts()
  2050.         {
  2051.             List<BodyPart> Result = null;
  2052.             FindUnsupportedParts(ref Result);
  2053.             return Result;
  2054.         }
  2055.  
  2056.         public bool HasLaterality(int checkLaterality)
  2057.         {
  2058.             return (Laterality & checkLaterality) == checkLaterality;
  2059.         }
  2060.  
  2061.         public bool IsFirstSlotForEquipped()
  2062.         {
  2063.             if (Equipped == null) return false;
  2064.             if (ParentBody != null) return ParentBody.FindEquippedItem(Equipped) == this;
  2065.             // without a parent body, FindEquippedItem(Equipped) will always be 'this'
  2066.             return true;
  2067.         }
  2068.  
  2069.         public bool IsFirstSlotForCybernetics()
  2070.         {
  2071.             if (Cybernetics == null) return false;
  2072.             if (ParentBody != null) return ParentBody.FindCybernetics(Cybernetics) == this;
  2073.             // without a parent body, FindCybernetics(Cybernetics) will always be 'this'
  2074.             return true;
  2075.         }
  2076.  
  2077.         public void GetTypeArmorInfo(string ForType, ref GameObject First, ref int Count, ref int AV, ref int DV)
  2078.         {
  2079.             if (ForType == Type)
  2080.             {
  2081.                 Count++;
  2082.                 if (Equipped != null)
  2083.                 {
  2084.                     Armor pArmor = Equipped.GetPart<Armor>();
  2085.                     if (pArmor != null && (pArmor.WornOn == Type || pArmor.WornOn == "*") && IsFirstSlotForEquipped())
  2086.                     {
  2087.                         if (First == null) First = Equipped;
  2088.                         AV += pArmor.AV;
  2089.                         DV += pArmor.DV;
  2090.                     }
  2091.                 }
  2092.             }
  2093.             if (Parts != null) foreach (BodyPart Part in Parts) Part.GetTypeArmorInfo(ForType, ref First, ref Count, ref AV, ref DV);
  2094.         }
  2095.  
  2096.         public void RecalculateArmor()
  2097.         {
  2098.             if (Equipped != null)
  2099.             {
  2100.                 Armor pArmor = Equipped.GetPart<Armor>();
  2101.                 if (pArmor != null && (pArmor.WornOn == Type || pArmor.WornOn == "*") && (pArmor.AV != 0 || pArmor.DV != 0) && IsFirstSlotForEquipped())
  2102.                 {
  2103.                     pArmor.RecalculateArmor();
  2104.                 }
  2105.             }
  2106.             if (Parts != null) foreach (BodyPart Part in Parts) Part.RecalculateArmor();
  2107.         }
  2108.  
  2109.         public void RecalculateArmorExcept(GameObject obj)
  2110.         {
  2111.             if (Equipped != null && Equipped != obj)
  2112.             {
  2113.                 Armor pArmor = Equipped.GetPart<Armor>();
  2114.                 if (pArmor != null && (pArmor.WornOn == Type || pArmor.WornOn == "*") && (pArmor.AV != 0 || pArmor.DV != 0) && IsFirstSlotForEquipped())
  2115.                 {
  2116.                     pArmor.RecalculateArmor();
  2117.                 }
  2118.             }
  2119.             if (Parts != null) foreach (BodyPart Part in Parts) Part.RecalculateArmor();
  2120.         }
  2121.  
  2122.         public void RecalculateTypeArmor(string ForType)
  2123.         {
  2124.             if (ForType == Type && Equipped != null)
  2125.             {
  2126.                 Armor pArmor = Equipped.GetPart<Armor>();
  2127.                 if (pArmor != null && (pArmor.WornOn == Type || pArmor.WornOn == "*") && (pArmor.AV != 0 || pArmor.DV != 0) && IsFirstSlotForEquipped())
  2128.                 {
  2129.                     pArmor.RecalculateArmor();
  2130.                 }
  2131.             }
  2132.             if (Parts != null) foreach (BodyPart Part in Parts) Part.RecalculateTypeArmor(ForType);
  2133.         }
  2134.  
  2135.         public void RecalculateTypeArmorExcept(string ForType, GameObject obj)
  2136.         {
  2137.             if (ForType == Type && Equipped != null && Equipped != obj)
  2138.             {
  2139.                 Armor pArmor = Equipped.GetPart<Armor>();
  2140.                 if (pArmor != null && (pArmor.WornOn == Type || pArmor.WornOn == "*") && (pArmor.AV != 0 || pArmor.DV != 0) && IsFirstSlotForEquipped())
  2141.                 {
  2142.                     pArmor.RecalculateArmor();
  2143.                 }
  2144.             }
  2145.             if (Parts != null) foreach (BodyPart Part in Parts) Part.RecalculateTypeArmor(ForType);
  2146.         }
  2147.  
  2148.         public void GetMissileWeapons(List<GameObject> List)
  2149.         {
  2150.             if (Equipped != null && !List.Contains(Equipped))
  2151.             {
  2152.                 MissileWeapon pMW = Equipped.GetPart<MissileWeapon>();
  2153.                 if (pMW != null && IsFirstSlotForEquipped() && Type == pMW.GetSlotType()) List.Add(Equipped);
  2154.             }
  2155.             if (Cybernetics != null && !List.Contains(Cybernetics))
  2156.             {
  2157.                 MissileWeapon pMW = Cybernetics.GetPart<MissileWeapon>();
  2158.                 if (pMW != null && IsFirstSlotForCybernetics() && Type == pMW.GetSlotType()) List.Add(Cybernetics);
  2159.             }
  2160.             if (Parts != null) foreach (BodyPart Part in Parts) Part.GetMissileWeapons(List);
  2161.         }
  2162.  
  2163.         public bool IsADefaultBehavior(GameObject obj)
  2164.         {
  2165.             if (obj == DefaultBehavior) return obj != null;
  2166.             if (Parts != null) foreach (BodyPart Part in Parts) if (Part.IsADefaultBehavior(obj)) return true;
  2167.             return false;
  2168.         }
  2169.  
  2170.         private static void GetCreatureFromSpec(string Blueprint, string Type, string Tag, string Base, Predicate<GameObjectBlueprint> Filter, ref GameObject Creature)
  2171.         {
  2172.             if (Blueprint != null)
  2173.             {
  2174.                 Creature = GameObject.create(Blueprint);
  2175.             }
  2176.             else
  2177.             if (Tag != null && Base != null)
  2178.             {
  2179.                 if (Filter == null)
  2180.                 {
  2181.                     Creature = Qud.API.EncountersAPI.GetACreature(BP => BP.HasPart("Body") && BP.HasTag(Tag) && BP.DescendsFrom(Base));
  2182.                 }
  2183.                 else
  2184.                 {
  2185.                     Creature = Qud.API.EncountersAPI.GetACreature(BP => BP.HasPart("Body") && BP.HasTag(Tag) && BP.DescendsFrom(Base) && Filter(BP));
  2186.                 }
  2187.             }
  2188.             else
  2189.             if (Tag != null)
  2190.             {
  2191.                 if (Filter == null)
  2192.                 {
  2193.                     Creature = Qud.API.EncountersAPI.GetACreature(BP => BP.HasPart("Body") && BP.HasTag(Tag));
  2194.                 }
  2195.                 else
  2196.                 {
  2197.                     Creature = Qud.API.EncountersAPI.GetACreature(BP => BP.HasPart("Body") && BP.HasTag(Tag) && Filter(BP));
  2198.                 }
  2199.             }
  2200.             else
  2201.             if (Base != null)
  2202.             {
  2203.                 if (Filter == null)
  2204.                 {
  2205.                     Creature = Qud.API.EncountersAPI.GetACreature(BP => BP.HasPart("Body") && BP.DescendsFrom(Base));
  2206.                 }
  2207.                 else
  2208.                 {
  2209.                     Creature = Qud.API.EncountersAPI.GetACreature(BP => BP.HasPart("Body") && BP.DescendsFrom(Base) && Filter(BP));
  2210.                 }
  2211.             }
  2212.             else
  2213.             {
  2214.                 if (Filter == null)
  2215.                 {
  2216.                     Creature = Qud.API.EncountersAPI.GetACreature(BP => BP.HasPart("Body"));
  2217.                 }
  2218.                 else
  2219.                 {
  2220.                     Creature = Qud.API.EncountersAPI.GetACreature(BP => BP.HasPart("Body") && Filter(BP));
  2221.                 }
  2222.             }
  2223.         }
  2224.  
  2225.         [NonSerialized] private static List<BodyPart> SeverWork = new List<BodyPart>(8);
  2226.  
  2227.         public static GameObject MakeSeveredBodyPart(string Blueprint = null, string Type = null, string Tag = null, string Base = null, Predicate<GameObjectBlueprint> Filter = null, GameObject PutIn = null)
  2228.         {
  2229.             GameObject creature = null;
  2230.             int tries = 0;
  2231.             while (++tries < 10)
  2232.             {
  2233.                 try
  2234.                 {
  2235.                     GetCreatureFromSpec(Blueprint, Type, Tag, Base, Filter, ref creature);
  2236.                     if (creature == null) return null;
  2237.                     Body pBody = creature.GetPart<Body>();
  2238.                     BodyPart part;
  2239.                     if (Type == null)
  2240.                     {
  2241.                         SeverWork.Clear();
  2242.                         foreach (BodyPart p in pBody.GetParts()) if (p.IsSeverable()) SeverWork.Add(p);
  2243.                         part = SeverWork.GetRandomElement();
  2244.                     }
  2245.                     else
  2246.                     {
  2247.                         part = pBody.GetFirstPart(Type);
  2248.                     }
  2249.                     if (part != null && part.IsSeverable())
  2250.                     {
  2251.                         GameObject obj = part.Dismember();
  2252.                         if (obj != null)
  2253.                         {
  2254.                             if (PutIn != null) PutIn.FireEvent(Event.New("CommandTakeObject", "Object", obj).SetSilent(true));
  2255.                             return obj;
  2256.                         }
  2257.                     }
  2258.                 }
  2259.                 finally
  2260.                 {
  2261.                     if (creature != null) creature.Obliterate();
  2262.                 }
  2263.                 if (Blueprint != null) return null;
  2264.             }
  2265.             return null;
  2266.         }
  2267.  
  2268.         public static void MakeSeveredBodyParts(int Number, string Blueprint = null, string Type = null, string Tag = null, string Base = null, Predicate<GameObjectBlueprint> Filter = null, GameObject PutIn = null, List<GameObject> Return = null)
  2269.         {
  2270.             GameObject creature = null;
  2271.             int origCount = 0;
  2272.             int tries = 0;
  2273.             int done = 0;
  2274.             while (++tries < 10)
  2275.             {
  2276.                 start:
  2277.                 GameObject prevCreature = creature;
  2278.                 GetCreatureFromSpec(Blueprint, Type, Tag, Base, Filter, ref creature);
  2279.                 if (creature == null)
  2280.                 {
  2281.                     break;
  2282.                 }
  2283.                 Body pBody = creature.GetPart<Body>();
  2284.                 BodyPart part;
  2285.                 if (Type == null)
  2286.                 {
  2287.                     SeverWork.Clear();
  2288.                     foreach (BodyPart p in pBody.GetParts()) if (p.IsSeverable()) SeverWork.Add(p);
  2289.                     part = SeverWork.GetRandomElement();
  2290.                     if (creature == prevCreature)
  2291.                     {
  2292.                         if (origCount - SeverWork.Count >= Number / 2)
  2293.                         {
  2294.                             creature.Obliterate();
  2295.                             creature = null;
  2296.                             goto start;
  2297.                         }
  2298.                     }
  2299.                     else
  2300.                     {
  2301.                         origCount = SeverWork.Count;
  2302.                     }
  2303.                 }
  2304.                 else
  2305.                 {
  2306.                     part = pBody.GetFirstPart(Type);
  2307.                 }
  2308.                 try
  2309.                 {
  2310.                     if (part != null && part.IsSeverable())
  2311.                     {
  2312.                         GameObject obj = part.Dismember();
  2313.                         if (obj != null)
  2314.                         {
  2315.                             if (PutIn != null) PutIn.FireEvent(Event.New("CommandTakeObject", "Object", obj).SetSilent(true));
  2316.                             if (Return != null) Return.Add(obj);
  2317.                             if (++done >= Number) break;
  2318.                             goto start;
  2319.                         }
  2320.                     }
  2321.                 }
  2322.                 finally
  2323.                 {
  2324.                     if (Blueprint == null)
  2325.                     {
  2326.                         creature.Obliterate();
  2327.                         creature = null;
  2328.                     }
  2329.                 }
  2330.                 if (Blueprint != null) break;
  2331.             }
  2332.             if (creature != null) creature.Obliterate();
  2333.         }
  2334.  
  2335.     }
  2336.  
  2337. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement