6 using Microsoft.Xna.Framework;
7 using Microsoft.Xna.Framework.Graphics;
9 using System.Collections.Generic;
13 using System.Xml.Linq;
18 partial class LimbJoint
23 float strength = MathHelper.Lerp(0, 1, MathUtils.InverseLerp(0, MathHelper.Pi, diff));
29 if (limbADeformation !=
null && limbBDeformation !=
null)
32 UpdateBend(LimbB, limbBDeformation, this.
LocalAnchorB, jointAngle);
39 Vector2 displayAnchor = ConvertUnits.ToDisplayUnits(localAnchor);
40 displayAnchor.Y = -displayAnchor.Y;
46 if (Math.Abs(localAnchor.X) > Math.Abs(localAnchor.Y))
48 if (localAnchor.X > 0.0f)
61 if (localAnchor.Y > 0.0f)
64 deformation.
BendUp = angle;
75 public void Draw(SpriteBatch spriteBatch)
109 private float wetTimer;
110 private float dripParticleTimer;
111 private float deadTimer;
112 private Color? randomColor;
118 private List<SpriteDeformation> Deformations {
get;
set; } =
new List<SpriteDeformation>();
119 private List<SpriteDeformation> NonConditionalDeformations {
get;
set; } =
new List<SpriteDeformation>();
120 private List<(ConditionalSprite, IEnumerable<SpriteDeformation>)> ConditionalDeformations {
get;
set; } =
new List<(ConditionalSprite, IEnumerable<SpriteDeformation>)>();
130 private SpriteBatch.EffectWithParams tintEffectParams;
131 private SpriteBatch.EffectWithParams huskSpriteParams;
140 var conditionalSprite =
ConditionalSprites.FirstOrDefault(c => c.Exclusive && c.IsActive && c.DeformableSprite !=
null);
141 if (conditionalSprite !=
null)
143 return conditionalSprite.DeformableSprite;
152 public List<DecorativeSprite>
DecorativeSprites {
get;
private set; } =
new List<DecorativeSprite>();
158 var conditionalSprite =
ConditionalSprites.FirstOrDefault(c => c.Exclusive && c.IsActive && c.ActiveSprite !=
null);
159 if (conditionalSprite !=
null)
161 return conditionalSprite.ActiveSprite;
190 set =>
Params.Hide = value;
193 public List<ConditionalSprite>
ConditionalSprites {
get;
private set; } =
new List<ConditionalSprite>();
194 private Dictionary<DecorativeSprite, SpriteState> spriteAnimState =
new Dictionary<DecorativeSprite, SpriteState>();
195 private Dictionary<int, List<DecorativeSprite>> DecorativeSpriteGroups =
new Dictionary<int, List<DecorativeSprite>>();
199 public float RotationState;
200 public float OffsetState;
201 public Vector2 RandomOffsetMultiplier =
new Vector2(Rand.Range(-1.0f, 1.0f), Rand.Range(-1.0f, 1.0f));
202 public float RandomRotationFactor = Rand.Range(0.0f, 1.0f);
203 public float RandomScaleFactor = Rand.Range(0.0f, 1.0f);
204 public bool IsActive =
true;
224 private float damageOverlayStrength;
227 get {
return damageOverlayStrength; }
228 set { damageOverlayStrength = MathHelper.Clamp(value, 0.0f, 1.0f); }
231 private float burnOverLayStrength;
234 get {
return burnOverLayStrength; }
235 set { burnOverLayStrength = MathHelper.Clamp(value, 0.0f, 1.0f); }
240 private readonly List<WearableSprite> wearableTypeHidingSprites =
new List<WearableSprite>();
241 private readonly HashSet<WearableType> wearableTypesToHide =
new HashSet<WearableType>();
242 private bool enableHuskSprite;
247 return enableHuskSprite;
251 if (enableHuskSprite == value) {
return; }
252 enableHuskSprite = value;
253 if (enableHuskSprite)
262 if (enableHuskSprite)
278 for (
int i = 0; i <
Params.decorativeSpriteParams.Count; i++)
280 var param =
Params.decorativeSpriteParams[i];
281 var decorativeSprite =
new DecorativeSprite(param.Element, file: GetSpritePath(param.Element, param, ref _texturePath));
283 int groupID = decorativeSprite.RandomGroupID;
284 if (!DecorativeSpriteGroups.ContainsKey(groupID))
286 DecorativeSpriteGroups.Add(groupID,
new List<DecorativeSprite>());
288 DecorativeSpriteGroups[groupID].Add(decorativeSprite);
289 spriteAnimState.Add(decorativeSprite,
new SpriteState());
293 foreach (var subElement
in element.
Elements())
295 switch (subElement.Name.ToString().ToLowerInvariant())
298 Sprite =
new Sprite(subElement, file: GetSpritePath(subElement,
Params.normalSpriteParams, ref _texturePath), sourceRectScale: sourceRectScale);
300 case "damagedsprite":
301 DamagedSprite =
new Sprite(subElement, file: GetSpritePath(subElement,
Params.damagedSpriteParams, ref _damagedTexturePath), sourceRectScale: sourceRectScale);
303 case "conditionalsprite":
304 var conditionalSprite =
new ConditionalSprite(subElement, GetConditionalTarget(), file: GetSpritePath(subElement,
null, ref _texturePath), sourceRectScale: sourceRectScale);
306 if (conditionalSprite.DeformableSprite !=
null)
308 var conditionalDeformations = CreateDeformations(subElement.GetChildElement(
"deformablesprite"));
309 Deformations.AddRange(conditionalDeformations);
310 ConditionalDeformations.Add((conditionalSprite, conditionalDeformations));
313 case "deformablesprite":
314 _deformSprite =
new DeformableSprite(subElement, filePath: GetSpritePath(subElement,
Params.deformSpriteParams, ref _texturePath), sourceRectScale: sourceRectScale);
315 var deformations = CreateDeformations(subElement);
316 Deformations.AddRange(deformations);
317 NonConditionalDeformations.AddRange(deformations);
320 randomColor = subElement.GetAttributeColorArray(
"colors",
null)?.GetRandomUnsynced();
321 if (randomColor.HasValue)
323 Params.GetSprite().Color = randomColor.Value;
332 if (randomColor.HasValue)
340 ContentPath tintMaskPath = subElement.GetAttributeContentPath(
"texture");
341 if (!tintMaskPath.IsNullOrWhiteSpace())
343 TintMask =
new Sprite(subElement, file: GetSpritePath(tintMaskPath), sourceRectScale: sourceRectScale);
349 ContentPath huskMaskPath = subElement.GetAttributeContentPath(
"texture");
350 if (!huskMaskPath.IsNullOrWhiteSpace())
352 HuskMask =
new Sprite(subElement, file: GetSpritePath(huskMaskPath), sourceRectScale: sourceRectScale);
357 ISerializableEntity GetConditionalTarget()
359 ISerializableEntity targetEntity;
360 string target = subElement.GetAttributeString(
"target",
null);
361 if (
string.Equals(target,
"character", StringComparison.OrdinalIgnoreCase))
372 IEnumerable<SpriteDeformation> CreateDeformations(XElement e)
374 List<SpriteDeformation> deformations =
new List<SpriteDeformation>();
375 foreach (XElement animationElement
in e.GetChildElements(
"spritedeformation"))
377 int sync = animationElement.GetAttributeInt(
"sync", -1);
382 string typeName = animationElement.GetAttributeString(
"type",
"").ToLowerInvariant();
384 .Where(l => l !=
null)
385 .SelectMany(l => l.Deformations)
386 .FirstOrDefault(d => d.TypeName == typeName && d.Sync == sync);
388 if (deformation ==
null)
391 if (deformation !=
null)
396 if (deformation !=
null)
398 deformations.Add(deformation);
408 private void RefreshDeformations()
422 foreach (var conditionalDeformation
in ConditionalDeformations)
424 if (conditionalDeformation.Item1.IsActive)
438 Sprite =
new Sprite(source, file: GetSpritePath(source,
Params.normalSpriteParams, ref _texturePath));
455 var source = conditionalSprite.ActiveSprite.SourceElement;
456 conditionalSprite.Remove();
462 var source = decorativeSprite.Sprite.SourceElement;
463 decorativeSprite.Remove();
468 private void CalculateHeadPosition(
Sprite sprite)
474 private string _texturePath;
475 private string _damagedTexturePath;
476 private string GetSpritePath(ContentXElement element, SpriteParams spriteParams, ref
string path)
480 if (spriteParams !=
null)
492 texturePath = parentRagdollParams.OriginalElement?.GetAttributeContentPath(
"texture");
496 path = GetSpritePath(texturePath);
500 ContentPath texturePath = element.GetAttributeContentPath(
"texture");
501 texturePath = texturePath.IsNullOrWhiteSpace()
504 path = GetSpritePath(texturePath);
515 string spritePath = texturePath.
Value;
516 string spritePathWithTags = spritePath;
517 if (characterInfo !=
null)
519 spritePath = characterInfo.
ReplaceVars(spritePath);
524 characterInfo.
SpriteTags.ForEach(tag => tags += $
"[{tag}]");
526 spritePathWithTags = Path.Combine(
527 Path.GetDirectoryName(spritePath),
528 Path.GetFileNameWithoutExtension(spritePath) + tags + Path.GetExtension(spritePath));
531 return File.Exists(spritePathWithTags) ? spritePathWithTags : spritePath;
535 private string GetSpritePath(
ContentPath texturePath)
541 partial
void LoadParamsProjSpecific()
544 Sprite?.LoadParams(
Params.normalSpriteParams, isFlipped);
553 partial
void AddDamageProjSpecific(
bool playSound, AttackResult result)
555 float bleedingDamage = 0;
558 foreach (var affliction
in result.Afflictions)
560 if (affliction is AfflictionBleeding bleeding && bleeding.Prefab.DamageParticles)
562 bleedingDamage += affliction.GetVitalityDecrease(
null);
567 foreach (var affliction
in result.Afflictions)
569 if (affliction.Prefab.DamageParticles && affliction.Prefab.AfflictionType == AfflictionPrefab.DamageType)
571 damage += affliction.GetVitalityDecrease(
null);
574 float damageMultiplier = 1;
575 float bleedingDamageMultiplier = 1;
576 foreach (DamageModifier damageModifier
in result.AppliedDamageModifiers)
578 if (damageModifier.MatchesAfflictionType(AfflictionPrefab.DamageType))
580 damageMultiplier *= damageModifier.DamageMultiplier;
582 else if (damageModifier.MatchesAfflictionType(AfflictionPrefab.BleedingType))
584 bleedingDamageMultiplier *= damageModifier.DamageMultiplier;
589 string damageSoundType = (bleedingDamage > damage) ?
"LimbSlash" :
"LimbBlunt";
590 foreach (DamageModifier damageModifier
in result.AppliedDamageModifiers)
592 if (!
string.IsNullOrWhiteSpace(damageModifier.DamageSound))
594 damageSoundType = damageModifier.DamageSound;
598 SoundPlayer.PlayDamageSound(damageSoundType, Math.Max(damage, bleedingDamage),
WorldPosition);
602 float damageParticleAmount = damage < 1 ? 0 : Math.Min(damage / 5, 1.0f) * damageMultiplier;
603 if (damageParticleAmount > 0.001f)
607 if (emitter?.Prefab ==
null) {
continue; }
611 foreach (DamageModifier damageModifier
in result.AppliedDamageModifiers)
613 if (damageModifier.DamageMultiplier > 0 && !
string.IsNullOrWhiteSpace(damageModifier.DamageParticle))
623 if (bleedingDamage > 0)
625 float bloodParticleAmount = Math.Min(bleedingDamage / 5, 1.0f) * bleedingDamageMultiplier;
626 float bloodParticleSize = MathHelper.Clamp(bleedingDamage / 5, 0.1f, 1.0f);
630 if (emitter?.Prefab ==
null) {
continue; }
638 partial
void UpdateProjSpecific(
float deltaTime)
644 var spriteParams =
Params.GetSprite();
645 if (spriteParams !=
null && spriteParams.DeadColorTime > 0 && deadTimer < spriteParams.DeadColorTime)
647 deadTimer += deltaTime;
657 wetTimer -= deltaTime * 0.1f;
660 dripParticleTimer += wetTimer * deltaTime *
Mass * (wetTimer > 0.9f ? 50.0f : 5.0f);
661 if (dripParticleTimer > 1.0f)
664 GameMain.ParticleManager.CreateParticle(
666 WorldPosition + Rand.Vector(Rand.Range(0.0f, ConvertUnits.ToDisplayUnits(dropRadius))),
669 dripParticleTimer = 0.0f;
676 conditionalSprite.CheckConditionals();
694 UpdateSpriteStates(deltaTime);
695 RefreshDeformations();
698 public void Draw(SpriteBatch spriteBatch,
Camera cam, Color? overrideColor =
null,
bool disableDeformations =
false)
700 var spriteParams =
Params.GetSprite();
701 if (spriteParams ==
null ||
Alpha <= 0) {
return; }
702 float burn = spriteParams.IgnoreTint ? 0 : burnOverLayStrength;
703 float brightness = Math.Max(1.0f - burn, 0.2f);
704 Color tintedColor = spriteParams.Color;
705 if (!spriteParams.IgnoreTint)
721 Color color =
new Color(tintedColor.Multiply(brightness), tintedColor.A);
722 Color colorWithoutTint =
new Color(spriteParams.Color.Multiply(brightness), spriteParams.Color.A);
723 Color blankColor =
new Color(brightness, brightness, brightness, 1);
726 color = Color.Lerp(color, spriteParams.DeadColor, MathUtils.InverseLerp(0, spriteParams.DeadColorTime, deadTimer));
727 colorWithoutTint = Color.Lerp(colorWithoutTint, spriteParams.DeadColor, MathUtils.InverseLerp(0, spriteParams.DeadColorTime, deadTimer));
730 color = overrideColor ?? color;
731 colorWithoutTint = overrideColor ?? colorWithoutTint;
732 blankColor = overrideColor ?? blankColor;
752 bool hideLimb =
Hide ||
761 CalculateHeadPosition(activeSprite);
765 float depthStep = 0.000001f;
770 if (deformSprite !=
null && !disableDeformations)
775 deformSprite.Deform(deformation);
784 deformSprite.Reset();
790 bool useTintMask =
TintMask !=
null && spriteBatch.GetCurrentEffect() is
null;
791 if (useTintMask &&
Sprite?.Texture !=
null &&
TintMask?.Texture !=
null)
794 tintEffectParams.Params ??=
new Dictionary<string, object>();
795 var parameters = tintEffectParams.Params;
798 if (drawHuskSprite &&
HuskMask !=
null)
805 parameters[
"xCutoffTexture"] = GUI.WhiteTexture;
806 parameters[
"baseToCutoffSizeRatio"] = 1.0f;
810 spriteBatch.SwapEffect(tintEffectParams);
815 spriteBatch.SwapEffect(
null);
822 if (conditionalSprite.Exclusive) {
continue; }
823 if (!conditionalSprite.IsActive) {
continue; }
824 if (conditionalSprite.DeformableSprite !=
null)
826 var defSprite = conditionalSprite.DeformableSprite;
830 defSprite.Deform(deformation);
844 SpriteEffects spriteEffect = (dir ==
Direction.Right) ? SpriteEffects.None : SpriteEffects.FlipHorizontally;
849 float step = depthStep;
851 if (
Params.MirrorHorizontally)
853 spriteEffect = spriteEffect == SpriteEffects.None ? SpriteEffects.FlipHorizontally : SpriteEffects.None;
855 if (
Params.MirrorVertically)
857 spriteEffect |= SpriteEffects.FlipVertically;
859 if (onlyDrawable ==
null)
863 float alpha = Math.Min(herpesStrength * 2 / 100.0f, 1.0f);
864 DrawWearable(
HerpesSprite, depthStep, spriteBatch, blankColor, alpha: alpha, spriteEffect);
869 bool useTintEffect =
HuskMask !=
null && spriteBatch.GetCurrentEffect() is
null;
873 huskSpriteParams.Params ??=
new Dictionary<string, object>();
874 var parameters = huskSpriteParams.Params;
875 parameters[
"xCutoffTexture"] = GUI.WhiteTexture;
876 parameters[
"baseToCutoffSizeRatio"] = 1.0f;
877 spriteBatch.SwapEffect(huskSpriteParams);
879 DrawWearable(
HuskSprite, depthStep, spriteBatch, color, alpha: color.A / 255f, spriteEffect);
882 spriteBatch.SwapEffect(
null);
889 if (wearableTypesToHide.Contains(wearable.
Type))
895 DrawWearable(
HairWithHatSprite, depthStep, spriteBatch, blankColor, alpha: color.A / 255f, spriteEffect);
905 DrawWearable(wearable, depthStep, spriteBatch, blankColor, alpha: color.A / 255f, spriteEffect);
915 bool hiddenByOtherItem =
false;
918 if (otherWearable == wearable) {
continue; }
919 if (wearable.
CanBeHiddenByItem.Contains(otherWearable.WearableComponent.Item.Prefab.Identifier))
921 hiddenByOtherItem =
true;
926 if (otherWearable.WearableComponent.Item.HasTag(tag))
928 hiddenByOtherItem =
true;
933 if (hiddenByOtherItem) {
continue; }
935 DrawWearable(wearable, depthStep, spriteBatch, blankColor, alpha: color.A / 255f, spriteEffect);
939 if (!
Hide && onlyDrawable ==
null)
943 if (!spriteAnimState[decorativeSprite].IsActive) {
continue; }
944 Color c =
new Color(decorativeSprite.Color.R / 255f * brightness, decorativeSprite.Color.G / 255f * brightness, decorativeSprite.Color.B / 255f * brightness, decorativeSprite.Color.A / 255f);
947 c = Color.Lerp(c, spriteParams.DeadColor, MathUtils.InverseLerp(0,
Params.GetSprite().DeadColorTime, deadTimer));
949 c = overrideColor ?? c;
950 float rotation = decorativeSprite.GetRotation(ref spriteAnimState[decorativeSprite].RotationState, spriteAnimState[decorativeSprite].RandomRotationFactor);
951 Vector2 offset = decorativeSprite.GetOffset(ref spriteAnimState[decorativeSprite].OffsetState, spriteAnimState[decorativeSprite].RandomOffsetMultiplier) *
Scale;
954 Vector2 transformedOffset =
new Vector2(ca * offset.X + sa * offset.Y, -sa * offset.X + ca * offset.Y);
956 -
body.
Rotation + rotation, decorativeSprite.GetScale(spriteAnimState[decorativeSprite].RandomScaleFactor) *
Scale, spriteEffect,
957 depth: activeSprite.Depth - depthStep);
964 colorWithoutTint * damageOverlayStrength, activeSprite.Origin,
966 Scale, spriteEffect, activeSprite.Depth - depthStep * Math.Max(1,
WearingItems.Count * 2));
972 if (pullJoint !=
null)
974 Vector2 pos = ConvertUnits.ToDisplayUnits(pullJoint.WorldAnchorB);
975 GUI.DrawRectangle(spriteBatch,
new Rectangle((
int)pos.X, (
int)-pos.Y, 5, 5), GUIStyle.Red,
true);
978 bodyDrawPos.Y = -bodyDrawPos.Y;
981 Vector2 from = ConvertUnits.ToDisplayUnits(attachJoint.WorldAnchorA);
983 Vector2 to = ConvertUnits.ToDisplayUnits(attachJoint.WorldAnchorB);
986 var front = ConvertUnits.ToDisplayUnits(
body.
FarseerBody.GetWorldPoint(localFront));
988 GUI.DrawLine(spriteBatch, bodyDrawPos, front, Color.Yellow, width: 2);
989 GUI.DrawLine(spriteBatch, from, to, GUIStyle.Red, width: 1);
990 GUI.DrawRectangle(spriteBatch,
new Rectangle((
int)from.X, (
int)from.Y, 12, 12), Color.White,
true);
991 GUI.DrawRectangle(spriteBatch,
new Rectangle((
int)to.X, (
int)to.Y, 12, 12), Color.White,
true);
992 GUI.DrawRectangle(spriteBatch,
new Rectangle((
int)from.X, (
int)from.Y, 10, 10), Color.Blue,
true);
993 GUI.DrawRectangle(spriteBatch,
new Rectangle((
int)to.X, (
int)to.Y, 10, 10), GUIStyle.Red,
true);
994 GUI.DrawRectangle(spriteBatch,
new Rectangle((
int)front.X, (
int)front.Y, 10, 10), Color.Yellow,
true);
1009 alphaClipEffectParams?.Clear();
1011 wearableTypeHidingSprites.Clear();
1013 void addWearablesFrom(IReadOnlyList<WearableSprite> wearableSprites)
1015 if (wearableSprites.Count <= 0) {
return; }
1017 wearableTypeHidingSprites.AddRange(
1018 wearableSprites.Where(w => w.HideWearablesOfType.Count > 0));
1024 wearableTypesToHide.Clear();
1026 if (wearableTypeHidingSprites.Count <= 0) {
return; }
1034 private void UpdateSpriteStates(
float deltaTime)
1036 foreach (
int spriteGroup
in DecorativeSpriteGroups.Keys)
1038 for (
int i = 0; i < DecorativeSpriteGroups[spriteGroup].Count; i++)
1040 var decorativeSprite = DecorativeSpriteGroups[spriteGroup][i];
1041 if (decorativeSprite ==
null) {
continue; }
1042 if (spriteGroup > 0)
1054 var spriteState = spriteAnimState[decorativeSprite];
1055 spriteState.IsActive =
true;
1056 foreach (PropertyConditional conditional
in decorativeSprite.IsActiveConditionals)
1058 if (!conditional.Matches(
this))
1060 spriteState.IsActive =
false;
1064 if (!spriteState.IsActive) {
continue; }
1067 bool animate =
true;
1068 foreach (PropertyConditional conditional
in decorativeSprite.AnimationConditionals)
1070 if (!conditional.Matches(
this)) { animate =
false;
break; }
1072 if (!animate) {
continue; }
1073 spriteState.OffsetState += deltaTime;
1074 spriteState.RotationState += deltaTime;
1090 Color color = modifier.DamageMultiplier > 1 ? GUIStyle.Red : GUIStyle.Green;
1091 float size = ConvertUnits.ToDisplayUnits(
body.
GetSize().Length() / 2);
1099 thickness = (int)Math.Round(thickness / cam.Zoom);
1102 float constantOffset = -MathHelper.PiOver2;
1103 Vector2 armorSector = modifier.ArmorSectorInRadians;
1104 float armorSectorSize = Math.Abs(armorSector.X - armorSector.Y);
1105 float radians = armorSectorSize *
Dir;
1106 float armorSectorOffset = armorSector.X *
Dir;
1107 float finalOffset = bodyRotation + constantOffset + armorSectorOffset;
1108 ShapeExtensions.DrawSector(spriteBatch, startPos, size, radians, 40, color, finalOffset, thickness);
1118 CalculateDrawParameters(
WearableSprite wearable,
float depthStep, Color color,
float alpha)
1140 origin = sprite.Origin;
1157 depth = sprite.Depth - depthStep;
1159 if (depthLimb !=
null)
1161 depth = depthLimb.ActiveSprite.Depth - depthStep;
1165 Color wearableColor = Color.White;
1166 if (wearableItemComponent !=
null)
1169 if (wearableItemComponent.AllowedSlots.Contains(
InvSlotType.OuterClothes))
1173 if (wearableItemComponent.AllowedSlots.Contains(
InvSlotType.Bag))
1175 depth -= depthStep * 4;
1177 wearableColor = wearableItemComponent.Item.GetSpriteColor();
1190 float scale = wearable.
Scale;
1207 float finalAlpha = alpha * wearableColor.A;
1208 Color finalColor = color.Multiply(wearableColor);
1209 finalColor =
new Color(finalColor.R, finalColor.G, finalColor.B, (
byte)finalAlpha);
1211 return (finalColor, origin, rotation, scale, depth);
1214 private static Effect alphaClipEffect;
1215 private Dictionary<WearableSprite, Dictionary<string, object>> alphaClipEffectParams;
1216 private void ApplyAlphaClip(SpriteBatch spriteBatch, WearableSprite wearable, WearableSprite alphaClipper, SpriteEffects spriteEffect)
1218 SpriteRecorder.Command makeCommand(WearableSprite w)
1220 var (_, origin, rotation, scale, _)
1221 = CalculateDrawParameters(w, 0f, Color.White, 0f);
1223 var command = SpriteRecorder.Command.FromTransform(
1224 texture: w.Sprite.Texture,
1226 srcRect: w.Sprite.SourceRect,
1228 rotationRad: rotation,
1230 scale:
new Vector2(scale, scale),
1231 effects: spriteEffect,
1240 var (topLeft, bottomLeft, topRight) = spriteEffect
switch
1243 => (command.VertexTL, command.VertexBL, command.VertexTR),
1244 SpriteEffects.FlipHorizontally | SpriteEffects.FlipVertically
1245 => (command.VertexBR, command.VertexTR, command.VertexBL),
1246 SpriteEffects.FlipHorizontally
1247 => (command.VertexTR, command.VertexBR, command.VertexTL),
1248 SpriteEffects.FlipVertically
1249 => (command.VertexBL, command.VertexTL, command.VertexBR)
1254 Origin = topLeft.TextureCoordinate,
1255 I = topRight.TextureCoordinate - topLeft.TextureCoordinate,
1256 J = bottomLeft.TextureCoordinate - topLeft.TextureCoordinate
1261 Origin = topLeft.Position.DiscardZ(),
1262 I = topRight.Position.DiscardZ() - topLeft.Position.DiscardZ(),
1263 J = bottomLeft.Position.DiscardZ() - topLeft.Position.DiscardZ()
1267 var wearableCommand = makeCommand(wearable);
1268 var clipperCommand = makeCommand(alphaClipper);
1270 spacesFromCommand(wearable, wearableCommand, out var wearableTextureSpace, out var wearableWorldSpace);
1271 spacesFromCommand(alphaClipper, clipperCommand, out var clipperTextureSpace, out var clipperWorldSpace);
1273 var wearableUvToClipperUv =
1274 wearableTextureSpace.CanonicalToLocal
1275 * wearableWorldSpace.LocalToCanonical
1276 * clipperWorldSpace.CanonicalToLocal
1277 * clipperTextureSpace.LocalToCanonical;
1279 alphaClipEffect ??= EffectLoader.Load(
"Effects/wearableclip");
1280 alphaClipEffectParams ??=
new Dictionary<WearableSprite, Dictionary<string, object>>();
1281 if (!alphaClipEffectParams.ContainsKey(wearable)) { alphaClipEffectParams.Add(wearable,
new Dictionary<string, object>()); }
1283 var paramsToPass =
new SpriteBatch.EffectWithParams
1285 Effect = alphaClipEffect,
1286 Params = alphaClipEffectParams[wearable]
1289 paramsToPass.Params[
"wearableUvToClipperUv"] = wearableUvToClipperUv;
1290 paramsToPass.Params[
"stencilUVmin"] =
new Vector2(
1291 (
float)alphaClipper.Sprite.SourceRect.X / alphaClipper.Sprite.Texture.Width,
1292 (
float)alphaClipper.Sprite.SourceRect.Y / alphaClipper.Sprite.Texture.Height);
1293 paramsToPass.Params[
"stencilUVmax"] =
new Vector2(
1294 (
float)alphaClipper.Sprite.SourceRect.Right / alphaClipper.Sprite.Texture.Width,
1295 (
float)alphaClipper.Sprite.SourceRect.Bottom / alphaClipper.Sprite.Texture.Height);
1296 paramsToPass.Params[
"clipperTexelSize"] = 2f / alphaClipper.Sprite.Texture.Width;
1297 paramsToPass.Params[
"aCutoff"] = 2f / 255f;
1298 paramsToPass.Params[
"xTexture"] = wearable.Sprite.Texture;
1299 paramsToPass.Params[
"xStencil"] = alphaClipper.Sprite.Texture;
1300 spriteBatch.SwapEffect(paramsToPass);
1303 private void DrawWearable(WearableSprite wearable,
float depthStep, SpriteBatch spriteBatch, Color color,
float alpha, SpriteEffects spriteEffect)
1305 if (wearable.Sprite?.Texture ==
null) {
return; }
1306 var (finalColor, origin, rotation, scale, depth) = CalculateDrawParameters(wearable, depthStep, color, alpha);
1307 var prevEffect = spriteBatch.GetCurrentEffect();
1308 var alphaClipper =
WearingItems.Find(w => w.AlphaClipOtherWearables);
1309 bool shouldApplyAlphaClip = alphaClipper?.Sprite?.Texture !=
null && wearable != alphaClipper;
1310 if (shouldApplyAlphaClip)
1312 ApplyAlphaClip(spriteBatch, wearable, alphaClipper, spriteEffect);
1315 if (shouldApplyAlphaClip)
1317 spriteBatch.SwapEffect(effect: prevEffect);
1324 if (info ==
null) {
return null; }
1325 ContentXElement element = info.
FilterElements(info.Wearables, info.Head.Preset.TagSet,
type)?.FirstOrDefault();
1326 return element !=
null ?
new WearableSprite(element.GetChildElement(
"sprite"),
type) : null;
1329 partial
void RemoveProjSpecific()
AfflictionPrefab is a prefab that defines a type of affliction that can be applied to a character....
static readonly Identifier SpaceHerpesType
float GetAfflictionStrengthByType(Identifier afflictionType, bool allowLimbAfflictions=true)
readonly CharacterParams Params
CharacterHealth CharacterHealth
IEnumerable< ParticleEmitter > DamageEmitters
readonly CharacterPrefab Prefab
Identifier GetBaseCharacterSpeciesName()
readonly AnimController AnimController
IEnumerable< ParticleEmitter > BloodEmitters
Stores information about the Character that is needed between rounds in the menu etc....
void CalculateHeadPosition(Sprite sprite)
IEnumerable< ContentXElement > FilterElements(IEnumerable< ContentXElement > elements, ImmutableHashSet< Identifier > tags, WearableType? targetType=null)
List< Identifier > SpriteTags
void VerifySpriteTagsLoaded()
string ReplaceVars(string str)
static Point CalculateOffset(Sprite sprite, Point offset)
IEnumerable< ContentXElement > Elements()
static GameScreen GameScreen
Effect ThresholdTintEffect
float? OverrideLightSpriteAlpha
DeformableSprite DeformableLightSprite
SpriteEffects LightSpriteEffect
DeformableSprite DeformSprite
readonly Ragdoll ragdoll
Note that during the limb initialization, character.AnimController returns null, whereas this field i...
readonly Character character
List< DamageModifier > DamageModifiers
List< ConditionalSprite > ConditionalSprites
WearableSprite HerpesSprite
WearableSprite HuskSprite
readonly LimbParams Params
Sprite GetActiveSprite(bool excludeConditionalSprites=true)
DeformableSprite _deformSprite
void DrawDamageModifiers(SpriteBatch spriteBatch, Camera cam, Vector2 startPos, bool isScreenSpace)
static string GetSpritePath(ContentPath texturePath, CharacterInfo characterInfo)
Get the full path of a limb sprite, taking into account tags, gender and head id
readonly List< WearableSprite > WearingItems
float TintHighlightThreshold
WearableSprite HairWithHatSprite
void Draw(SpriteBatch spriteBatch, Camera cam, Color? overrideColor=null, bool disableDeformations=false)
List< DecorativeSprite > DecorativeSprites
const float SoundInterval
Color InitialLightSourceColor
List< SpriteDeformation > ActiveDeformations
Limb(Ragdoll ragdoll, Character character, LimbParams limbParams)
float LastAttackSoundTime
readonly List< WearableSprite > OtherWearables
void UpdateWearableTypesToHide()
float? InitialLightSpriteAlpha
float DamageOverlayStrength
float TintHighlightMultiplier
float BurnOverlayStrength
float Alpha
Can be used by status effects
void UpdateDeformations(float deltaTime)
void Draw(SpriteBatch spriteBatch)
readonly ParticleEmitterPrefab Prefab
void Emit(float deltaTime, Vector2 position, Hull? hullGuess=null, float angle=0.0f, float particleRotation=0.0f, float velocityMultiplier=1.0f, float sizeMultiplier=1.0f, float amountMultiplier=1.0f, Color? colorMultiplier=null, ParticlePrefab? overrideParticle=null, bool mirrorAngle=false, Tuple< Vector2, Vector2 >? tracerPoints=null)
ParticlePrefab? ParticlePrefab
static ParticlePrefab FindPrefab(string prefabName)
DrawTargetType DrawTarget
Vector2 GetLocalFront(float? spritesheetRotation=null)
Returns the farthest point towards the forward of the body. For capsules and circles,...
void Draw(DeformableSprite deformSprite, Camera cam, Vector2 scale, Color color, bool invert=false)
void UpdateDrawPosition(bool interpolate=true)
ContentPackage? ContentPackage
abstract RagdollParams RagdollParams
HashSet< SpriteDeformation > SpriteDeformations
Limb GetLimb(LimbType limbType, bool excludeSevered=true)
Note that if there are multiple limbs of the same type, only the first (valid) limb is returned.
float SourceRectScale
Multiplies both the position and the size of the source rects. Used for scaling the textures when we ...
void Draw(ISpriteBatch spriteBatch, Vector2 pos, float rotate=0.0f, float scale=1.0f, SpriteEffects spriteEffect=SpriteEffects.None)
ContentXElement SourceElement
Reference to the xml element from where the sprite was created. Can be null if the sprite was not def...
ImmutableHashSet< Identifier > CanBeHiddenByItem
Tags or identifiers of items that can hide this one.
bool InheritScale
Does the wearable inherit all the scalings of the wearer? Also the wearable's own scale is used!
List< WearableType > HideWearablesOfType
Wearable WearableComponent
bool CanBeHiddenByOtherWearables