1 using Microsoft.Xna.Framework;
3 using System.Collections.Generic;
4 using System.Diagnostics;
52 [
Serialize(
"",
IsPropertySaveable.Yes, description:
"Default path for the limb sprite textures. Used only if the limb specific path for the limb is not defined"),
Editable]
56 public Color Color {
get;
set; }
59 "Defines the \"forward direction\" of the sprites. Should be configured as the direction pointing outwards from the main limb. " +
60 "Incorrectly defined orientations may lead to limbs being rotated incorrectly when e.g. when the character aims or flips to face a different direction. " +
61 "Can be overridden per sprite by setting a value for Limb's 'Sprite Orientation'."),
Editable(-360, 360)]
74 private float limbScale;
78 get {
return limbScale; }
82 private float jointScale;
86 get {
return jointScale; }
105 [
Serialize(45f,
IsPropertySaveable.Yes, description:
"How high from the ground the main collider levitates when the character is standing? Doesn't affect swimming."),
Editable(0f, 1000f)]
108 [
Serialize(50f,
IsPropertySaveable.Yes, description:
"How much impact is required before the character takes impact damage?"),
Editable(MinValueFloat = 0, MaxValueFloat = 1000)]
128 private static readonly Dictionary<Identifier, Dictionary<string, RagdollParams>> allRagdolls =
new Dictionary<Identifier, Dictionary<string, RagdollParams>>();
130 public List<ColliderParams>
Colliders {
get;
private set; } =
new List<ColliderParams>();
131 public List<LimbParams>
Limbs {
get;
private set; } =
new List<LimbParams>();
132 public List<JointParams>
Joints {
get;
private set; } =
new List<JointParams>();
139 public static string GetDefaultFileName(Identifier speciesName) => $
"{speciesName.Value.CapitaliseFirstInvariant()}DefaultRagdoll";
141 => IO.Path.Combine(
GetFolder(speciesName, contentPackage), $
"{GetDefaultFileName(speciesName)}.xml");
146 if (prefab?.ConfigElement ==
null)
148 DebugConsole.ThrowError($
"Failed to find config file for '{speciesName}'", contentPackage: contentPackage);
156 Debug.Assert(filePath !=
null);
157 Debug.Assert(root !=
null);
159 if (folder.IsNullOrEmpty() || folder.Equals(
"default", StringComparison.OrdinalIgnoreCase))
161 folder = IO.Path.Combine(IO.Path.GetDirectoryName(filePath),
"Ragdolls") + IO.Path.DirectorySeparatorChar;
163 return folder.CleanUpPathCrossPlatform(correctFilenameCase:
true);
170 XElement mainElement = characterParams.VariantFile?.Root ?? characterParams.
MainElement;
176 Debug.Assert(contentPackage !=
null);
177 if (characterRootElement.IsOverride())
179 characterRootElement = characterRootElement.FirstElement();
181 Identifier ragdollSpecies = speciesName;
182 Identifier variantOf = characterRootElement.VariantOf();
183 if (characterRootElement !=
null && (characterRootElement.GetChildElement(
"ragdolls") ?? characterRootElement.GetChildElement(
"ragdoll")) is XElement ragdollElement)
185 if ((ragdollElement.GetAttributeContentPath(
"path", contentPackage) ?? ragdollElement.GetAttributeContentPath(
"file", contentPackage)) is
ContentPath path)
189 else if (!variantOf.IsEmpty)
191 string folder = ragdollElement.GetAttributeContentPath(
"folder", contentPackage)?.Value;
192 if (folder.IsNullOrEmpty() || folder.Equals(
"default", StringComparison.OrdinalIgnoreCase))
197 ragdollSpecies = prefab.GetBaseCharacterSpeciesName(variantOf);
205 ragdollSpecies = prefab.GetBaseCharacterSpeciesName(variantOf);
213 Debug.Assert(!speciesName.IsEmpty);
214 Debug.Assert(!ragdollSpecies.IsEmpty);
216 string fileName =
null;
219 if (!file.TryGet(out fileName))
221 file.TryGet(out contentPath);
223 Debug.Assert(!fileName.IsNullOrWhiteSpace() || !contentPath.IsNullOrWhiteSpace());
225 Debug.Assert(contentPackage !=
null);
226 if (!allRagdolls.TryGetValue(speciesName, out Dictionary<string, RagdollParams> ragdolls))
228 ragdolls =
new Dictionary<string, RagdollParams>();
229 allRagdolls.Add(speciesName, ragdolls);
237 if (!contentPath.IsNullOrEmpty())
240 T ragdollInstance =
new T();
241 if (ragdollInstance.Load(contentPath, ragdollSpecies))
243 ragdolls.TryAdd(contentPath.
Value, ragdollInstance);
244 return ragdollInstance;
248 DebugConsole.ThrowError($
"[AnimationParams] Failed to load an animation {ragdollInstance} from {contentPath.Value} for the character {speciesName}. Using the default ragdoll.", contentPackage: contentPackage);
253 string folder =
GetFolder(ragdollSpecies);
254 if (Directory.Exists(folder))
256 var files = Directory.GetFiles(folder).OrderBy(f => f, StringComparer.OrdinalIgnoreCase);
259 DebugConsole.ThrowError($
"[RagdollParams] Could not find any ragdoll files from the folder: {folder}. Using the default ragdoll.", contentPackage: contentPackage);
264 if (
string.IsNullOrEmpty(fileName))
269 selectedFile = files.FirstOrDefault(f => f.Contains(defaultFileName, StringComparison.OrdinalIgnoreCase)) ?? files.First();
273 selectedFile = files.FirstOrDefault(f => IO.Path.GetFileNameWithoutExtension(f).Equals(fileName, StringComparison.OrdinalIgnoreCase));
274 if (selectedFile ==
null)
276 DebugConsole.ThrowError($
"[RagdollParams] Could not find a ragdoll file that matches the name {fileName}. Using the default ragdoll.", contentPackage: contentPackage);
284 DebugConsole.ThrowError($
"[RagdollParams] Invalid directory: {folder}. Using the default ragdoll.", contentPackage: contentPackage);
288 Debug.Assert(selectedFile !=
null);
289 DebugConsole.Log($
"[RagdollParams] Loading the ragdoll from {selectedFile}.");
293 ragdolls.TryAdd(key, r);
298 throw new Exception($
"[RagdollParams] Failed to load ragdoll {r.Name} from {selectedFile} for the character {speciesName}.");
310 if (allRagdolls.ContainsKey(speciesName))
312 DebugConsole.NewMessage($
"[RagdollParams] Removing the old ragdolls from {speciesName}.", Color.Red);
313 allRagdolls.Remove(speciesName);
315 var ragdolls =
new Dictionary<string, RagdollParams>();
316 allRagdolls.Add(speciesName, ragdolls);
319 doc =
new XDocument(mainElement)
323 instance.UpdatePath(contentPath);
324 instance.IsLoaded = instance.Deserialize(mainElement);
326 instance.Load(contentPath, speciesName);
327 ragdolls.Add(instance.FileNameWithoutExtension, instance);
328 DebugConsole.NewMessage(
"[RagdollParams] New default ragdoll params successfully created at " + fullPath, Color.NavajoWhite);
338 base.UpdatePath(fullPath);
344 if (allRagdolls.TryGetValue(
SpeciesName, out Dictionary<string, RagdollParams> ragdolls))
346 ragdolls.Remove(fileName);
348 base.UpdatePath(fullPath);
349 if (ragdolls !=
null)
351 if (!ragdolls.ContainsKey(fileName))
353 ragdolls.Add(fileName,
this);
359 public bool Save(
string fileNameWithoutExtension =
null)
362 GetAllSubParams().ForEach(p => p.SetCurrentElementAsOriginalElement());
364 return base.Save(fileNameWithoutExtension,
new XmlWriterSettings
367 OmitXmlDeclaration =
true,
368 NewLineOnAttributes =
false
376 isVariantScaleApplied =
false;
397 public override bool Reset(
bool forceReload =
false)
412 if (
MainElement?.GetChildElements(
"collider") is { } colliderElements)
414 for (
int i = 0; i < colliderElements.Count(); i++)
416 var element = colliderElements.ElementAt(i);
417 string name = i > 0 ?
"Secondary Collider" :
"Main Collider";
426 if (
MainElement?.GetChildElements(
"limb") is { } childElements)
428 foreach (var element
in childElements)
445 public bool Deserialize(XElement element =
null,
bool alsoChildren =
true,
bool recursive =
true)
447 if (base.Deserialize(element))
458 public bool Serialize(XElement element =
null,
bool alsoChildren =
true,
bool recursive =
true)
460 if (base.Serialize(element))
474 base.AddToEditor(editor);
478 foreach (var subParam
in subParams)
480 subParam.AddToEditor(editor,
true, space);
493 private bool isVariantScaleApplied;
496 if (isVariantScaleApplied) {
return; }
497 if (variantFile ==
null) {
return; }
498 if (variantFile.GetRootExcludingOverride() is XElement root)
500 if ((root.GetChildElement(
"ragdoll") ?? root.GetChildElement(
"ragdolls")) is XElement ragdollElement)
502 float scaleMultiplier = ragdollElement.GetAttributeFloat(
"scalemultiplier", 1f);
505 float textureScale = ragdollElement.GetAttributeFloat(nameof(
TextureScale), 0f);
506 if (textureScale > 0)
511 float sourceRectScale = ragdollElement.GetAttributeFloat(nameof(
SourceRectScale), 0f);
512 if (sourceRectScale > 0)
519 isVariantScaleApplied =
true;
531 DebugConsole.ThrowError(
"[RagdollParams] The source XML Document is null!");
541 copy.CreateColliders();
556 DebugConsole.ThrowError(
"[RagdollParams] The source XML Element of the given RagdollParams is null!",
564 if (sourceSubParams.Count != subParams.Count)
566 DebugConsole.ThrowError(
"[RagdollParams] The count of the sub params differs! Failed to revert to the previous snapshot! Please reset the ragdoll to undo the changes.",
570 for (
int i = 0; i < subParams.Count; i++)
572 var subSubParams = subParams[i].SubParams;
573 if (subSubParams.Count != sourceSubParams[i].SubParams.Count)
575 DebugConsole.ThrowError(
"[RagdollParams] The count of the sub sub params differs! Failed to revert to the previous snapshot! Please reset the ragdoll to undo the changes.",
579 subParams[i].Deserialize(sourceSubParams[i].Element, recursive:
false);
580 for (
int j = 0; j < subSubParams.Count; j++)
582 subSubParams[j].Deserialize(sourceSubParams[i].SubParams[j].Element, recursive:
false);
598 if (
string.IsNullOrWhiteSpace(name))
633 [
Serialize(0f,
IsPropertySaveable.Yes, description:
"Default 0 (Can't be severed when the creature is alive). Modifies the severance probability (defined per item/attack) when the character is alive. Currently only affects non-humanoid ragdolls. Also note that if CanBeSevered is false, this property doesn't have any effect."),
Editable(MinValueFloat = 0, MaxValueFloat = 10, ValueStep = 0.1f, DecimalCount = 2)]
679 public List<DamageModifierParams>
DamageModifiers {
get;
private set; } =
new List<DamageModifierParams>();
687 if (
string.IsNullOrWhiteSpace(name))
704 public int ID {
get;
set; }
706 [
Serialize(
LimbType.None,
IsPropertySaveable.Yes, description:
"The limb type affects many things, like the animations. Torso or Head are considered as the main limbs. Every character should have at least one Torso or Head."),
Editable()]
735 "Defines the \"forward direction\" of the sprite. Should be configured as the direction pointing outwards from the main limb." +
736 "Incorrectly defined orientations may lead to limbs being rotated incorrectly when e.g. when the character aims or flips to face a different direction. " +
737 "Overrides the value of 'Spritesheet Orientation' for this limb."),
Editable(-360, 360, ValueStep = 90, DecimalCount = 0)]
740 [
Serialize(
LimbType.None,
IsPropertySaveable.Yes, description:
"If set, the limb sprite will use the same sprite depth as the specified limb. Generally only useful for limbs that get added on the ragdoll on the fly (e.g. extra limbs added via gene splicing).")]
755 [
Serialize(10f,
IsPropertySaveable.Yes, description:
"The more the density the heavier the limb is."),
Editable(MinValueFloat = 0.01f, MaxValueFloat = 100, DecimalCount = 2)]
767 [
Serialize(
"0, 0",
IsPropertySaveable.Yes, description:
"The position which is used to lead the IK chain to the IK goal. Only applicable if the limb is hand or foot."),
Editable()]
770 [
Serialize(
"0, 0",
IsPropertySaveable.Yes, description:
"Only applicable if this limb is a foot. Determines the \"neutral position\" of the foot relative to a joint determined by the \"RefJoint\" parameter. For example, a value of {-100, 0} would mean that the foot is positioned on the floor, 100 units behind the reference joint."),
Editable()]
773 [
Serialize(-1,
IsPropertySaveable.Yes, description:
"The id of the refecence joint. Determines which joint is used as the \"neutral x-position\" for the foot movement. For example in the case of a humanoid-shaped characters this would usually be the waist. The position can be offset using the StepOffset parameter. Only applicable if this limb is a foot."),
Editable()]
776 [
Serialize(
"0, 0",
IsPropertySaveable.Yes, description:
"Relative offset for the mouth position (starting from the center). Only applicable for LimbType.Head. Used for eating."),
Editable(DecimalCount = 2, MinValueFloat = -10f, MaxValueFloat = 10f)]
788 [
Serialize(1f,
IsPropertySaveable.Yes, description:
"How much damage must be done by the attack in order to be able to cut off the limb. Note that it's evaluated after the damage modifiers."),
Editable(DecimalCount = 0, MinValueFloat = 0, MaxValueFloat = 1000)]
791 [
Serialize(
true,
IsPropertySaveable.Yes, description:
"Disable if you don't want to allow severing this joint while the creature is alive. Note: Does nothing if the 'Severance Probability Modifier' in the joint settings is 0 (default). Also note that the setting doesn't override certain limitations, e.g. severing the main limb, or legs of a walking creature is not allowed."),
Editable]
798 [
Serialize(
false,
IsPropertySaveable.Yes, description:
"Only applied when the limb is of type Tail. If none of the tails have been defined to use the angle and an angle is defined in the animation parameters, the first tail limb is used."),
Editable]
857 [
Serialize(
true,
IsPropertySaveable.Yes, description:
"Can the limb enter submarines? Only valid if the ragdoll's CanEnterSubmarine is set to Partial, otherwise the limb can enter if the ragdoll can."),
Editable]
863 if (spriteElement !=
null)
869 if (damagedSpriteElement !=
null)
876 if (deformSpriteElement !=
null)
881 foreach (var decorativeSpriteElement
in element.GetChildElements(
"decorativesprite"))
887 var attackElement = element.GetChildElement(
"attack");
888 if (attackElement !=
null)
893 foreach (var damageElement
in element.GetChildElements(
"damagemodifier"))
899 var soundElement = element.GetChildElement(
"sound");
900 if (soundElement !=
null)
905 var lightElement = element.GetChildElement(
"lightsource");
906 if (lightElement !=
null)
915 if (
Attack !=
null) {
return false; }
924 if (
Sound !=
null) {
return false; }
927 return Sound !=
null;
934 new XElement(
"lighttexture",
new XAttribute(
"texture",
"Content/Lights/pointlight_bright.png")));
944 if (RemoveSubParam(
Attack))
954 if (RemoveSubParam(
Sound))
976 subParam = constructor(element,
Ragdoll);
977 if (collection !=
null && filter !=
null)
979 if (filter(collection)) {
return false; }
983 collection?.Add(subParam);
984 return subParam !=
null;
989 if (subParam ==
null || subParam.Element ==
null || subParam.Element.Parent ==
null) {
return false; }
990 if (collection !=
null && !collection.Contains(subParam)) {
return false; }
991 if (!
SubParams.Contains(subParam)) {
return false; }
992 collection?.Remove(subParam);
994 subParam.Element.Remove();
1013 base.Deserialize(element, recursive);
1020 base.Serialize(element, recursive);
1052 [
Serialize(0f,
IsPropertySaveable.Yes, description:
"The Z-depth of the limb relative to other limbs of the same character. 1 is front, 0 is behind."),
Editable(MinValueFloat = 0, MaxValueFloat = 1, DecimalCount = 3)]
1062 public Color Color {
get;
set; }
1067 [
Serialize(0f,
IsPropertySaveable.Yes,
"How long it takes to fade into the dead color? 0 = Not applied."),
Editable(DecimalCount = 1, MinValueFloat = 0, MaxValueFloat = 10)]
1070 public override string Name =>
"Sprite";
1082 Deformations =
new Dictionary<SpriteDeformationParams, XElement>();
1083 foreach (var deformationElement
in element.GetChildElements(
"spritedeformation"))
1085 string typeName = deformationElement.GetAttributeString(
"type",
null) ?? deformationElement.GetAttributeString(
"typename",
string.Empty);
1087 switch (typeName.ToLowerInvariant())
1102 case "reacttotriggerers":
1106 DebugConsole.ThrowError($
"SpriteDeformationParams not implemented: '{typeName}'",
1107 contentPackage: element.ContentPackage);
1110 if (deformation !=
null)
1112 deformation.
Type = typeName;
1120 public Dictionary<SpriteDeformationParams, XElement>
Deformations {
get;
private set; }
1124 base.Deserialize(element, recursive);
1131 base.Serialize(element, recursive);
1146 private string name;
1152 if (
string.IsNullOrWhiteSpace(name))
1186 public override string Name =>
"Light Texture";
1212 if (lightTextureElement !=
null)
1222 base.Deserialize(element, recursive);
1229 base.Serialize(element, recursive);
1254 base.Deserialize(element, recursive);
1261 base.Serialize(element, recursive);
1277 new XAttribute(
"identifier",
"internaldamage"),
1278 new XAttribute(
"strength", 0f),
1279 new XAttribute(
"probability", 1.0f));
1289 affliction.Remove();
1306 base.Deserialize(element, recursive);
1313 base.Serialize(element, recursive);
1327 public override string Name =>
"Sound";
1330 public string Tag {
get;
private set; }
1337 public virtual string Name {
get;
set; }
1341 public List<SubParam>
SubParams {
get;
set; } =
new List<SubParam>();
1363 SubParams.ForEach(sp => sp.Deserialize(recursive:
true));
1374 SubParams.ForEach(sp => sp.Serialize(recursive:
true));
1382 SubParams.ForEach(sp => sp.SetCurrentElementAsOriginalElement());
1404 foreach (var deformation
in deformSpriteParams.Deformation.Deformations.Keys)
1420 foreach (var affliction
in attackParams.Attack.Afflictions.Keys)
1437 SubParams.ForEach(sp => sp.AddToEditor(editor,
true));
1443 CanBeFocused =
false
Attacks are used to deal damage to characters, structures and items. They can be defined in the weapo...
void Deserialize(ContentXElement element, string parentDebugName)
void Serialize(ContentXElement element)
void ReloadAfflictions(ContentXElement element, string parentDebugName)
Contains character data that should be editable in the character editor.
static CharacterPrefab Find(Predicate< CharacterPrefab > predicate)
static CharacterPrefab FindBySpeciesName(Identifier speciesName)
ContentXElement ConfigElement
static readonly PrefabCollection< CharacterPrefab > Prefabs
readonly ContentPath Path
static ContentPath FromRaw(string? rawValue)
void Add(ContentXElement elem)
ContentPackage? ContentPackage
IEnumerable< ContentXElement > GetChildElements(string name)
ContentXElement? GetChildElement(string name)
void Serialize(XElement element)
void Deserialize(XElement element)
Dictionary< Identifier, SerializableProperty > SerializableProperties
string FileNameWithoutExtension
ContentXElement OriginalElement
virtual ContentXElement? MainElement
static FishRagdollParams GetDefaultRagdollParams(Character character)
RectTransform RectTransform
GUIFrame Content
A frame that contains the contents of the listbox. The frame itself is not rendered.
static HumanRagdollParams GetDefaultRagdollParams(Character character)
readonly ContentFile ContentFile
override bool Serialize(ContentXElement element=null, bool recursive=true)
bool RemoveAffliction(XElement affliction)
AttackParams(ContentXElement element, RagdollParams ragdoll)
override bool Deserialize(ContentXElement element=null, bool recursive=true)
ColliderParams(ContentXElement element, RagdollParams ragdoll, string name=null)
DamageModifier DamageModifier
DamageModifierParams(ContentXElement element, RagdollParams ragdoll)
override bool Deserialize(ContentXElement element=null, bool recursive=true)
override bool Serialize(ContentXElement element=null, bool recursive=true)
DecorativeSpriteParams(ContentXElement element, RagdollParams ragdoll)
override bool Deserialize(ContentXElement element=null, bool recursive=true)
override bool Serialize(ContentXElement element=null, bool recursive=true)
DecorativeSprite DecorativeSprite
float LowerLimit
In degrees.
override string GenerateName()
Vector2 Limb1Anchor
Should be converted to sim units.
float SeveranceProbabilityModifier
JointParams(ContentXElement element, RagdollParams ragdoll)
Vector2 Limb2Anchor
Should be converted to sim units.
float UpperLimit
In degrees.
LightTexture(ContentXElement element, RagdollParams ragdoll)
override bool Deserialize(ContentXElement element=null, bool recursive=true)
Lights.LightSourceParams LightSource
LightSourceParams(ContentXElement element, RagdollParams ragdoll)
override bool Serialize(ContentXElement element=null, bool recursive=true)
Vector2 BlinkTextureOffsetOut
LimbParams(ContentXElement element, RagdollParams ragdoll)
readonly DeformSpriteParams deformSpriteParams
LimbType InheritLimbDepth
TransitionMode BlinkTransitionIn
TransitionMode BlinkTransitionOut
float SineAmplitudeMultiplier
List< DamageModifierParams > DamageModifiers
override string GenerateName()
readonly List< DecorativeSpriteParams > decorativeSpriteParams
readonly SpriteParams damagedSpriteParams
readonly SpriteParams normalSpriteParams
float GetSpriteOrientation()
The orientation of the sprite as drawn on the sprite sheet (in radians).
float AttackForceMultiplier
LightSourceParams LightSource
bool RemoveDamageModifier(DamageModifierParams damageModifier)
float SineFrequencyMultiplier
float GetSpriteOrientationInDegrees()
bool UseTextureOffsetForBlinking
Vector2 BlinkTextureOffsetIn
bool RemoveSubParam< T >(T subParam, IList< T > collection=null)
bool TryAddSubParam< T >(ContentXElement element, Func< ContentXElement, RagdollParams, T > constructor, out T subParam, IList< T > collection=null, Func< IList< T >, bool > filter=null)
SoundParams(ContentXElement element, RagdollParams ragdoll)
SpriteParams(ContentXElement element, RagdollParams ragdoll)
List< SubParam > SubParams
virtual bool Serialize(ContentXElement element=null, bool recursive=true)
virtual void AddToEditor(ParamsEditor editor, bool recursive=true, int space=0)
virtual void SetCurrentElementAsOriginalElement()
ContentXElement CreateElement(string name, params object[] attrs)
Dictionary< Identifier, SerializableProperty > SerializableProperties
Dictionary< Affliction, SerializableEntityEditor > AfflictionEditors
SubParam(ContentXElement element, RagdollParams ragdoll)
ContentXElement OriginalElement
virtual bool Deserialize(ContentXElement element=null, bool recursive=true)
virtual string GenerateName()
SerializableEntityEditor SerializableEntityEditor
override bool Reset(bool forceReload=false)
Resets the current properties to the xml (stored in memory). Force reload reloads the file from disk.
float SourceRectScale
Multiplies both the position and the size of the source rects. Used for scaling the textures when we ...
float SpritesheetOrientation
static T CreateDefault< T >(string fullPath, Identifier speciesName, XElement mainElement)
Creates a default ragdoll for the species using a predefined configuration. Note: Use only to create ...
bool Serialize(XElement element=null, bool alsoChildren=true, bool recursive=true)
override void UpdatePath(ContentPath fullPath)
IEnumerable< SubParam > GetAllSubParams()
static string GetDefaultFile(Identifier speciesName, ContentPackage contentPackage=null)
void TryApplyVariantScale(XDocument variantFile)
bool Save(string fileNameWithoutExtension=null)
void AddToEditor(ParamsEditor editor, bool alsoChildren=true, int space=0)
static T GetDefaultRagdollParams< T >(Character character)
static string GetFolder(Identifier speciesName, ContentPackage contentPackage=null)
bool Deserialize(XElement element=null, bool alsoChildren=true, bool recursive=true)
List< ColliderParams > Colliders
static string GetDefaultFileName(Identifier speciesName)
static T GetRagdollParams< T >(Identifier speciesName, Identifier ragdollSpecies, Either< string, ContentPath > file, ContentPackage contentPackage)
float TextureScale
Can be used for scaling the textures without having to readjust the entire ragdoll....
float ColliderHeightFromFloor
bool IsSpritesheetOrientationHorizontal
void Apply()
Applies the current properties to the xml definition without saving to file.
bool Load(ContentPath file, Identifier speciesName)
List< JointParams > Joints
void AddCustomContent(GUIComponent component, int childIndex)
static Dictionary< Identifier, SerializableProperty > DeserializeProperties(object obj, XElement element=null)
static void SerializeProperties(ISerializableEntity obj, XElement element, bool saveIfDefault=false, bool ignoreEditable=false)
@ Partial
The ragdoll's limbs can enter the sub, but the collider can't. Can be used to e.g....
@ True
Can fully enter a submarine. Make sure to only allow this on small/medium sized creatures that can re...
@ False
No part of the ragdoll can go inside a submarine