2 using Microsoft.Xna.Framework;
5 using System.Collections.Generic;
8 using System.Collections.Immutable;
9 using System.ComponentModel;
11 using Microsoft.Xna.Framework.Graphics;
40 public override ImmutableHashSet<Identifier>
Tags {
get; }
46 public override ImmutableHashSet<string>
Aliases {
get; }
49 public bool Body {
get;
private set; }
61 [
Serialize(
"0.0,0.0",
IsPropertySaveable.No, description:
"Offset of the physics body from the center of the structure in pixels.")]
64 [
Serialize(
false,
IsPropertySaveable.No, description:
"Is the structure a platform (i.e. a \"floor\" the players can pass through)? Only relevant if the structure has a physics body.")]
67 [
Serialize(
false,
IsPropertySaveable.No, description:
"Can items like signal components be attached on this structure? Should be enabled on structures like decorative background walls.")]
80 get {
return health; }
81 private set { health = Math.Max(value,
MinHealth); }
87 [
Serialize(
false,
IsPropertySaveable.No, description:
"Should the structure cast shadows and obstruct visibility when LOS is enabled?")]
93 [
Serialize(45.0f,
IsPropertySaveable.No, description:
"Angle of the stairs in degrees. Only relevant if StairDirection is something else than None.")]
99 [
Serialize(
"0,0",
IsPropertySaveable.Yes, description:
"Size of the structure in pixels. If not set, the size is determined, based on the attributes width and height, and if those aren't defined either, based on the size of the structure's sprite.")]
100 public Vector2
Size {
get;
private set; }
105 [
Serialize(
"shrapnel",
IsPropertySaveable.Yes, description:
"Identifier of the particles emitted when something damages the wall.")]
116 MathHelper.Clamp(value.X, 0.01f, 10),
117 MathHelper.Clamp(value.Y, 0.01f, 10));
123 Identifier identifier = base.DetermineIdentifier(element);
124 string originalName = element.GetAttributeString(
"name",
"");
125 if (identifier.IsEmpty && !
string.IsNullOrEmpty(originalName))
127 string categoryStr = element.GetAttributeString(
"category",
"Misc");
130 identifier = $
"legacystructure_{originalName.Replace(" ", "")}".ToIdentifier();
148 Name = TextManager.Get(nameIdentifier.IsEmpty
149 ? $
"EntityName.{Identifier}"
150 : $
"EntityName.{nameIdentifier}",
151 $
"EntityName.{fallbackNameIdentifier}");
153 if (parentType ==
"wrecked")
155 Name = TextManager.GetWithVariable(
"wreckeditemformat",
"[name]",
Name);
162 var tags =
new HashSet<Identifier>();
164 if (
string.IsNullOrEmpty(joinedTags)) joinedTags = element.
GetAttributeString(
"Tags",
"");
165 foreach (
string tag
in joinedTags.Split(
','))
167 tags.Add(tag.Trim().ToIdentifier());
170 if (element.GetAttribute(
"ishorizontal") !=
null)
172 IsHorizontal = element.GetAttributeBool(
"ishorizontal",
false);
176 var decorativeSprites =
new List<DecorativeSprite>();
177 var decorativeSpriteGroups =
new Dictionary<int, List<DecorativeSprite>>();
179 foreach (var subElement
in element.Elements())
181 switch (subElement.Name.ToString().ToLowerInvariant())
185 if (subElement.GetAttribute(
"sourcerect") ==
null &&
186 subElement.GetAttribute(
"sheetindex") ==
null)
188 DebugConsole.ThrowErrorLocalized(
"Warning - sprite sourcerect not configured for structure \"" +
Name +
"\"!");
191 if (subElement.GetAttributeBool(
"fliphorizontal",
false))
192 Sprite.effects = SpriteEffects.FlipHorizontally;
193 if (subElement.GetAttributeBool(
"flipvertical",
false))
194 Sprite.effects = SpriteEffects.FlipVertically;
199 if (subElement.GetAttribute(
"name") ==
null && !
Name.IsNullOrWhiteSpace())
205 case "backgroundsprite":
207 if (subElement.GetAttribute(
"sourcerect") ==
null &&
Sprite !=
null)
216 if (subElement.GetAttributeBool(
"fliphorizontal",
false)) {
BackgroundSprite.effects = SpriteEffects.FlipHorizontally; }
217 if (subElement.GetAttributeBool(
"flipvertical",
false)) {
BackgroundSprite.effects = SpriteEffects.FlipVertically; }
218 BackgroundSpriteColor = subElement.GetAttributeColor(
"color", Color.White);
221 case "decorativesprite":
223 string decorativeSpriteFolder =
"";
224 if (subElement.DoesAttributeReferenceFileNameAlone(
"texture"))
226 decorativeSpriteFolder = Path.GetDirectoryName(file.Path);
230 DecorativeSprite decorativeSprite =
null;
231 if (subElement.GetAttribute(
"texture") ==
null)
233 groupID = subElement.GetAttributeInt(
"randomgroupid", 0);
237 decorativeSprite =
new DecorativeSprite(subElement, decorativeSpriteFolder, lazyLoad:
true);
238 decorativeSprites.Add(decorativeSprite);
239 groupID = decorativeSprite.RandomGroupID;
241 if (!decorativeSpriteGroups.ContainsKey(groupID))
243 decorativeSpriteGroups.Add(groupID,
new List<DecorativeSprite>());
245 decorativeSpriteGroups[groupID].Add(decorativeSprite);
251 DecorativeSprites = decorativeSprites.ToImmutableArray();
252 DecorativeSpriteGroups = decorativeSpriteGroups.Select(kvp => (kvp.Key, kvp.Value.ToImmutableArray())).ToImmutableDictionary();
255 string categoryStr = element.GetAttributeString(
"category",
"Structure");
263 (element.GetAttributeStringArray(
"aliases",
null, convertToLowerInvariant:
true) ??
264 element.GetAttributeStringArray(
"Aliases", Array.Empty<
string>(), convertToLowerInvariant:
true)).ToImmutableHashSet();
266 string nonTranslatedName = element.GetAttributeString(
"name",
null) ?? element.Name.ToString();
267 Aliases.Add(nonTranslatedName.ToLowerInvariant());
272 tags.Add(
"wall".ToIdentifier());
278 if (element.GetAttribute(
"size") ==
null)
281 if (element.GetAttribute(
"width") ==
null && element.GetAttribute(
"height") ==
null)
288 element.GetAttributeFloat(
"width", 0.0f),
289 element.GetAttributeFloat(
"height", 0.0f));
294 if (categoryStr.Equals(
"Thalamus", StringComparison.OrdinalIgnoreCase))
302 DebugConsole.ThrowError(
303 "Structure prefab \"" +
Name.
Value +
"\" has no identifier. All structure prefabs have a unique identifier string that's used to differentiate between items during saving and loading.",
311 DebugConsole.AddWarning($
"Structure \"{(Identifier == Identifier.Empty ? Name : Identifier.Value)}\" has a hard-coded name, and won't be localized to other languages.",
317 Tags = tags.ToImmutableHashSet();
323 throw new NotImplementedException();
string? GetAttributeString(string key, string? def)
Identifier GetAttributeIdentifier(string key, string def)
LocalizedString Fallback(LocalizedString fallback, bool useDefaultLanguageIfFound=true)
Use this text instead if the original text cannot be found.
void LoadDescription(ContentXElement element)
readonly Identifier Identifier
static Dictionary< Identifier, SerializableProperty > DeserializeProperties(object obj, XElement element=null)
Vector2 RelativeOrigin
0 - 1
Identifier EntityIdentifier
Identifier of the Map Entity so that we can link the sprite to its owner.
override string OriginalName
override bool CanSpriteFlipY
override ImmutableHashSet< Identifier > AllowedLinks
readonly Sprite BackgroundSprite
static readonly PrefabCollection< StructurePrefab > Prefabs
bool AllowRotatingInEditor
override ImmutableHashSet< Identifier > Tags
override MapEntityCategory Category
override void CreateInstance(Rectangle rect)
bool IndestructibleInOutposts
override LocalizedString Name
StructurePrefab(ContentXElement element, StructureFile file)
override ImmutableHashSet< string > Aliases
readonly ContentXElement ConfigElement
override bool CanSpriteFlipX
override Identifier DetermineIdentifier(XElement element)
readonly? bool IsHorizontal
If null, the orientation is determined automatically based on the dimensions of the structure instanc...