5 using System.Collections.Generic;
6 using Microsoft.Xna.Framework;
7 using Microsoft.Xna.Framework.Graphics;
11 using System.Collections.Immutable;
15 partial class CharacterInfo
17 private static Sprite infoAreaPortraitBG;
22 private Sprite disguisedPortrait;
23 private List<WearableSprite> disguisedAttachmentSprites;
24 private Vector2? disguisedSheetIndex;
25 private Sprite disguisedJobIcon;
26 private Color disguisedJobColor;
27 private Color disguisedHairColor;
28 private Color disguisedFacialHairColor;
29 private Color disguisedSkinColor;
32 private float tintHighlightThreshold;
33 private float tintHighlightMultiplier;
37 infoAreaPortraitBG = GUIStyle.GetComponentStyle(
"InfoAreaPortraitBG")?.GetDefaultSprite();
38 new Sprite(
"Content/UI/InventoryUIAtlas.png",
new Rectangle(833, 298, 142, 98),
null, 0);
44 if (maskElement !=
null)
47 if (!tintMaskPath.IsNullOrEmpty())
50 tintMask =
new Sprite(maskElement, file:
Limb.GetSpritePath(tintMaskPath,
this));
51 tintHighlightThreshold = maskElement.
GetAttributeFloat(
"highlightthreshold", 0.6f);
52 tintHighlightMultiplier = maskElement.
GetAttributeFloat(
"highlightmultiplier", 0.8f);
61 RelativeSpacing = 0.05f
68 onDraw: (sb, component) => DrawInfoFrameCharacterIcon(sb, component.Rect));
70 GUIFont font = paddedFrame.Rect.Width < 280 ? GUIStyle.SmallFont : GUIStyle.Font;
74 RelativeSpacing = 0.02f,
78 Color? nameColor =
null;
81 GUITextBlock characterNameBlock =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.25f), headerTextArea.RectTransform), ToolBox.LimitString(
Name, GUIStyle.Font, headerTextArea.Rect.Width), textColor: nameColor, font: GUIStyle.Font)
84 Padding = Vector4.Zero
87 if (permissionIcon !=
null)
89 Point iconSize = permissionIcon.SourceRect.Size;
90 int iconWidth = (int)((
float)characterNameBlock.
Rect.Height / iconSize.Y * iconSize.X);
91 new GUIImage(
new RectTransform(
new Point(iconWidth, characterNameBlock.
Rect.Height), characterNameBlock.
RectTransform) { AbsoluteOffset = new Point(-iconWidth - 2, 0) }, permissionIcon) { IgnoreLayoutGroups =
true };
98 Padding = Vector4.Zero
108 Padding = Vector4.Zero
113 text: TextManager.Get(
"ClientPermission.ManageBotTalents"), style:
"GUIButtonSmall")
116 UserData = TalentMenu.ManageBotTalentsButtonUserData,
119 AutoScaleHorizontal =
true
123 if (TalentMenu.CanManageTalents(
this))
125 manageTalentButton.
Enabled =
true;
136 skills.Sort((s1, s2) => -s1.Level.CompareTo(s2.Level));
138 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), skillsArea.RectTransform), TextManager.AddPunctuation(
':', TextManager.Get(
"skills"),
string.Empty), font: font) { Padding = Vector4.Zero };
140 foreach (
Skill skill
in skills)
142 Color textColor = Color.White * (0.5f + skill.
Level / 200.0f);
144 var skillName =
new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), skillsArea.RectTransform), skill.
DisplayName, textColor: textColor, font: font) { Padding = Vector4.Zero };
146 float modifiedSkillLevel = skill.
Level;
151 if (!MathUtils.NearlyEqual(MathF.Round(modifiedSkillLevel), MathF.Round(skill.
Level)))
153 int skillChange = (int)MathF.Round(modifiedSkillLevel - skill.
Level);
154 string changeText = $
"{(skillChange > 0 ? "+
" : "") + skillChange}";
155 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 1.0f), skillName.RectTransform), $
"{(int)skill.Level} ({changeText})", textColor: textColor, font: font, textAlignment: Alignment.CenterRight);
159 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 1.0f), skillName.RectTransform), ((
int)skill.
Level).ToString(), textColor: textColor, font: font, textAlignment: Alignment.CenterRight);
171 TextManager.Get(
"deceased") +
"\n" +
174 new GUITextBlock(
new RectTransform(
new Vector2(1.0f, 0.0f), deadArea.RectTransform), deadDescription, textColor: GUIStyle.Red, font: font, textAlignment: Alignment.TopLeft) { Padding = Vector4.Zero };
187 private void DrawInfoFrameCharacterIcon(SpriteBatch sb, Rectangle componentRect)
190 Vector2 targetAreaSize = componentRect.Size.ToVector2();
191 float scale = Math.Min(targetAreaSize.X / _headSprite.
size.X, targetAreaSize.Y / _headSprite.
size.Y);
192 DrawIcon(sb, componentRect.Location.ToVector2() + _headSprite.
size / 2 * scale, targetAreaSize);
202 Color? textColor =
null;
207 onDraw: (sb, component) =>
DrawIcon(sb, component.Rect.Center.ToVector2(), targetAreaSize: component.Rect.Size.ToVector2()));
211 partial
void OnSkillChanged(Identifier skillIdentifier,
float prevLevel,
float newLevel)
217 bool specialIncrease = Math.Abs(newLevel - prevLevel) >= 1.0f;
219 if ((
int)newLevel > (
int)prevLevel)
222 int increase = Math.Max((
int)newLevel - (
int)prevLevel, 1);
225 "+[value] "+ TextManager.Get(
"SkillName." + skillIdentifier).Value,
226 specialIncrease ? GUIStyle.Orange : GUIStyle.Green,
231 partial
void OnExperienceChanged(
int prevAmount,
int newAmount)
235 GameSession.TabMenuInstance?.OnExperienceChanged(
Character);
237 if (newAmount > prevAmount)
239 int increase = newAmount - prevAmount;
241 "+[value] " + TextManager.Get(
"experienceshort").Value,
246 private void GetDisguisedSprites(
IdCard idCard)
248 if (idCard.
Item.
Tags ==
string.Empty)
return;
252 var readTags = idCard.
Item.
Tags.Split(
',')
253 .Where(s => s.Contains(
':'))
254 .Select(s => s.Split(
':'))
255 .Select(s => (s[0].ToIdentifier(),s[1]))
256 .ToImmutableDictionary();
258 if (readTags.None()) {
return; }
286 partial
void LoadAttachmentSprites()
288 if (attachmentSprites ==
null)
290 attachmentSprites =
new List<WearableSprite>();
307 if (sprite ==
null) {
return; }
315 if (infoAreaPortraitBG ==
null) {
return; }
316 infoAreaPortraitBG.Draw(spriteBatch, HUDLayoutSettings.BottomRightInfoArea.Location.ToVector2(), Color.White, Vector2.Zero, 0.0f,
318 HUDLayoutSettings.BottomRightInfoArea.Width / (
float)infoAreaPortraitBG.SourceRect.Width,
319 HUDLayoutSettings.BottomRightInfoArea.Height / (
float)infoAreaPortraitBG.SourceRect.Height));
325 const int million = 1000000;
326 int xfraction = (int)(HUDLayoutSettings.BottomRightInfoArea.Width * 0.2f);
327 int yoffset = GUI.IntScale(6);
331 LocalizedString str = walletAmount >= million ? TextManager.Get(
"crewwallet.balance.toomuchtoshow") : TextManager.FormatCurrency(walletAmount);
332 Vector2 size = GUIStyle.Font.MeasureString(str);
333 int barHeight = GUI.IntScale(18);
335 Rectangle barRect =
new Rectangle((
int)(HUDLayoutSettings.BottomRightInfoArea.X + xfraction / 2.5f), HUDLayoutSettings.BottomRightInfoArea.Bottom - barHeight - yoffset, HUDLayoutSettings.BottomRightInfoArea.Width - xfraction, barHeight);
336 float textScale = Math.Max(0.1f, Math.Min(barRect.Width / size.X, barRect.Height / size.Y)) - 0.01f;
338 GUIStyle.WalletPortraitBG.Draw(spriteBatch, barRect, Color.White);
340 int iconSize = GUI.IntScale(28);
341 int iconXOffset = iconSize / 2;
342 Rectangle iconRect =
new Rectangle(barRect.Right - iconXOffset, barRect.Top - iconSize / 4, iconSize, iconSize);
343 GUIStyle.CrewWalletIconSmall.Draw(spriteBatch, iconRect, Color.White);
344 var (scaledTextSizeX, scaledTextSizeY) = size * textScale;
345 GUIStyle.Font.DrawString(spriteBatch, str,
new Vector2(barRect.Right - iconXOffset - scaledTextSizeX - GUI.IntScale(4), barRect.Center.Y - scaledTextSizeY / 2), GUIStyle.TextColorNormal, 0f, Vector2.Zero, textScale, SpriteEffects.None, 0f);
348 public void DrawPortrait(SpriteBatch spriteBatch, Vector2 screenPos, Vector2 offset,
float targetWidth,
bool flip =
false,
bool evaluateDisguise =
false)
354 List<WearableSprite> attachmentsToDraw;
357 Color facialHairColor;
372 sheetIndex = disguisedSheetIndex;
373 portraitToDraw = disguisedPortrait;
374 attachmentsToDraw = disguisedAttachmentSprites;
376 hairColor = disguisedHairColor;
377 facialHairColor = disguisedFacialHairColor;
378 skinColor = disguisedSkinColor;
381 if (portraitToDraw !=
null)
383 var currEffect = spriteBatch.GetCurrentEffect();
386 if (sheetIndex.HasValue)
388 SetHeadEffect(spriteBatch);
391 portraitToDraw.
Draw(spriteBatch, screenPos + offset, skinColor, portraitToDraw.
Origin, scale: scale, spriteEffect: flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
392 if (attachmentsToDraw !=
null)
394 float depthStep = 0.000001f;
395 foreach (var attachment
in attachmentsToDraw)
397 SetAttachmentEffect(spriteBatch, attachment);
398 DrawAttachmentSprite(spriteBatch, attachment, portraitToDraw, sheetIndex, screenPos + offset, scale, depthStep, GetAttachmentColor(attachment, hairColor, facialHairColor), flip ? SpriteEffects.FlipHorizontally : SpriteEffects.None);
399 depthStep += depthStep;
402 spriteBatch.SwapEffect(currEffect);
407 private SpriteBatch.EffectWithParams headEffectParameters;
408 private Dictionary<
WearableType, SpriteBatch.EffectWithParams> attachmentEffectParameters
409 =
new Dictionary<
WearableType, SpriteBatch.EffectWithParams>();
411 private void SetHeadEffect(SpriteBatch spriteBatch)
414 headEffectParameters.Params ??=
new Dictionary<string, object>();
416 headEffectParameters.Params[
"xTintMaskTexture"] = tintMask?.
Texture ?? GUI.WhiteTexture;
417 headEffectParameters.Params[
"xCutoffTexture"] = GUI.WhiteTexture;
418 headEffectParameters.Params[
"baseToCutoffSizeRatio"] = 1.0f;
419 headEffectParameters.Params[
"highlightThreshold"] = tintHighlightThreshold;
420 headEffectParameters.Params[
"highlightMultiplier"] = tintHighlightMultiplier;
421 spriteBatch.SwapEffect(headEffectParameters);
424 private void SetAttachmentEffect(SpriteBatch spriteBatch, WearableSprite attachment)
426 if (!attachmentEffectParameters.ContainsKey(attachment.Type))
428 attachmentEffectParameters.Add(attachment.Type,
new SpriteBatch.EffectWithParams(GameMain.GameScreen.ThresholdTintEffect,
new Dictionary<string, object>()));
430 var parameters = attachmentEffectParameters[attachment.Type].Params;
431 parameters[
"xBaseTexture"] = attachment.Sprite.Texture;
432 parameters[
"xTintMaskTexture"] = GUI.WhiteTexture;
433 parameters[
"xCutoffTexture"] = GUI.WhiteTexture;
434 parameters[
"baseToCutoffSizeRatio"] = 1.0f;
435 parameters[
"highlightThreshold"] = tintHighlightThreshold;
436 parameters[
"highlightMultiplier"] = tintHighlightMultiplier;
437 spriteBatch.SwapEffect(attachmentEffectParameters[attachment.Type]);
440 private Color GetAttachmentColor(WearableSprite attachment, Color hairColor, Color facialHairColor)
442 switch (attachment.Type)
448 return facialHairColor;
454 public void DrawIcon(SpriteBatch spriteBatch, Vector2 screenPos, Vector2 targetAreaSize)
457 if (headSprite !=
null)
459 var currEffect = spriteBatch.GetCurrentEffect();
460 float scale = Math.Min(targetAreaSize.X / headSprite.size.X, targetAreaSize.Y / headSprite.size.Y);
462 SetHeadEffect(spriteBatch);
463 headSprite.Draw(spriteBatch, screenPos, scale: scale, color:
Head.
SkinColor);
466 float depthStep = 0.000001f;
469 SetAttachmentEffect(spriteBatch, attachment);
471 depthStep += depthStep;
474 spriteBatch.SwapEffect(currEffect);
478 public void DrawJobIcon(SpriteBatch spriteBatch, Rectangle area,
bool evaluateDisguise =
false)
482 if (icon ==
null) {
return; }
485 icon.Draw(spriteBatch, area.Center.ToVector2(), iconColor, scale: Math.Min(area.Width / (
float)icon.SourceRect.Width, area.Height / (
float)icon.SourceRect.Height));
488 private void DrawAttachmentSprite(SpriteBatch spriteBatch,
WearableSprite attachment,
Sprite head, Vector2? sheetIndex, Vector2 drawPos,
float scale,
float depthStep, Color? color =
null, SpriteEffects spriteEffects = SpriteEffects.None)
496 else if (sheetIndex.HasValue)
518 depth = head.
Depth - depthStep;
520 attachment.
Sprite.
Draw(spriteBatch, drawPos, color ?? Color.White, origin, rotate: 0, scale: scale, depth: depth, spriteEffect: spriteEffects);
530 HashSet<Identifier> tagSet =
new HashSet<Identifier>();
531 for (
int i = 0; i < tagCount; i++)
537 int moustacheIndex = inc.
ReadByte();
538 int faceAttachmentIndex = inc.
ReadByte();
547 float minReputationToHire = 0.0f;
556 Dictionary<Identifier, float> skillLevels =
new Dictionary<Identifier, float>();
557 if (jobIdentifier > 0)
559 jobPrefab =
JobPrefab.
Prefabs.Find(jp => jp.UintIdentifier == jobIdentifier);
560 if (jobPrefab ==
null && requireJobPrefabFound)
562 throw new Exception($
"Error while reading {nameof(CharacterInfo)} received from the server: could not find a job prefab with the identifier \"{jobIdentifier}\".");
565 for (
int i = 0; i < skillCount; i++)
569 skillLevels.Add(skillIdentifier, skillLevel);
576 MinReputationToHire = (
factionId, minReputationToHire),
579 ch.RecreateHead(tagSet.ToImmutableHashSet(), hairIndex, beardIndex, moustacheIndex, faceAttachmentIndex);
580 ch.Head.SkinColor = skinColor;
581 ch.Head.HairColor = hairColor;
582 ch.Head.FacialHairColor = facialHairColor;
583 ch.SetPersonalityTrait();
584 ch.Job?.OverrideSkills(skillLevels);
596 onDraw: (sb, component) =>
DrawIcon(sb, component.Rect.Center.ToVector2(), targetAreaSize: component.Rect.Size.ToVector2()));
610 private readonly List<Sprite> characterSprites =
new List<Sprite>();
616 parentComponent = parent;
629 float contentWidth =
HasIcon ? 0.75f : 1.0f;
631 new RectTransform(
new Vector2(contentWidth, 1.0f), parentComponent.RectTransform,
633 { CanBeFocused =
false, CanTakeKeyBoardFocus =
false };
636 info.LoadHeadAttachments();
640 new RectTransform(
new Vector2(0.25f, 1.0f), parentComponent.RectTransform,
Anchor.CenterRight)
641 { RelativeOffset = new Vector2(-0.01f, 0.0f) });
644 RectTransform createItemRectTransform(Identifier labelTag,
float width = 0.6f)
649 TextManager.Get(labelTag), font: GUIStyle.SubHeadingFont);
654 return new RectTransform(
new Vector2(width, 1.0f), bottomItem.RectTransform,
Anchor.Center);
657 RectTransform menuCategoryRT = createItemRectTransform(info.Prefab.MenuCategoryVar, 1.0f);
663 RelativeSpacing = 0.05f
666 void createMenuCategoryButton(Identifier tag)
669 TextManager.Get(tag), style:
"ListBoxElement")
672 OnClicked = OpenHeadSelection,
673 Selected = info.Head.Preset.TagSet.Contains(tag)
677 foreach (var tag
in info.Prefab.VarTags[info.Prefab.MenuCategoryVar].OrderBy(t => t.Value).Reverse())
679 createMenuCategoryButton(tag);
682 List<GUIScrollBar> attachmentSliders =
new List<GUIScrollBar>();
683 void createAttachmentSlider(
int initialValue,
WearableType wearableType)
685 int attachmentCount = info.CountValidAttachmentsOfType(wearableType);
686 if (attachmentCount > 0)
688 var labelTag = wearableType ==
WearableType.FaceAttachment
689 ?
"FaceAttachment.Accessories".ToIdentifier()
690 : $
"FaceAttachment.{wearableType}".ToIdentifier();
691 var sliderItemRT = createItemRectTransform(labelTag);
695 Range =
new Vector2(0, attachmentCount),
697 OnMoved = (bar, scroll) => SwitchAttachment(bar, wearableType),
699 BarSize = 1.0f / (float)(attachmentCount + 1)
702 attachmentSliders.Add(slider);
706 createAttachmentSlider(info.Head.HairIndex,
WearableType.Hair);
707 createAttachmentSlider(info.Head.BeardIndex,
WearableType.Beard);
708 createAttachmentSlider(info.Head.MoustacheIndex,
WearableType.Moustache);
709 createAttachmentSlider(info.Head.FaceAttachmentIndex,
WearableType.FaceAttachment);
711 void createColorSelector(Identifier labelTag, IEnumerable<(Color Color,
float Commonness)> options, Func<Color> getter,
712 Action<Color> setter)
714 var selectorItemRT = createItemRectTransform(labelTag, 0.4f);
717 { AllowNonText =
true };
720 dropdown.ListBox.RectTransform.RelativeSize =
new Vector2(listBoxSize.X * 1.75f, listBoxSize.Y);
721 var dropdownButton = dropdown.GetChild<
GUIButton>();
725 { RelativeOffset = new Vector2(0.05f, 0.0f) }, style:
null);
726 Color? previewingColor =
null;
727 dropdown.OnSelected = (component, color) =>
729 previewingColor =
null;
730 setter((Color)color);
731 buttonFrame.Color = getter();
732 buttonFrame.HoverColor = getter();
735 buttonFrame.Color = getter();
736 buttonFrame.HoverColor = getter();
738 dropdown.ListBox.UseGridLayout =
true;
739 foreach (var option
in options)
744 dropdown.ListBox.Content.RectTransform),
745 style:
"ListBoxElement")
747 UserData = option.
Color,
756 Color = option.
Color,
757 HoverColor = option.Color,
758 OutlineColor = Color.Lerp(Color.Black, option.Color, 0.5f),
763 var childToSelect = dropdown.ListBox.Content.FindChild(c => (Color)c.UserData == getter());
764 dropdown.Select(dropdown.ListBox.Content.GetChildIndex(childToSelect));
768 onUpdate: (deltaTime, component) =>
770 if (GUI.MouseOn is GUIFrame { Parent: { } p } hoveredFrame && dropdown.ListBox.Content.
IsParentOf(hoveredFrame))
772 previewingColor ??= getter();
773 Color color = (Color)(dropdown.ListBox.Content.FindChild(c =>
774 c == hoveredFrame || c.IsParentOf(hoveredFrame))?.UserData ?? dropdown.SelectedData ?? getter());
776 buttonFrame.Color = getter();
777 buttonFrame.HoverColor = getter();
779 else if (previewingColor.HasValue)
781 setter(previewingColor.Value);
782 buttonFrame.Color = getter();
783 buttonFrame.HoverColor = getter();
784 previewingColor =
null;
788 CanBeFocused =
false,
793 if (info.CountValidAttachmentsOfType(
WearableType.Hair) > 0)
795 createColorSelector($
"Customization.{nameof(info.Head.HairColor)}".ToIdentifier(), info.HairColors,
796 () => info.Head.HairColor, (color) => info.Head.HairColor = color);
799 if (info.CountValidAttachmentsOfType(
WearableType.Moustache) > 0 ||
800 info.CountValidAttachmentsOfType(
WearableType.Beard) > 0)
802 createColorSelector($
"Customization.{nameof(info.Head.FacialHairColor)}".ToIdentifier(), info.FacialHairColors,
803 () => info.Head.FacialHairColor, (color) => info.Head.FacialHairColor = color);
806 createColorSelector($
"Customization.{nameof(info.Head.SkinColor)}".ToIdentifier(), info.SkinColors, () => info.Head.SkinColor,
807 (color) => info.Head.SkinColor = color);
809 new GUIButton(
new RectTransform(Vector2.One * 0.12f,
810 parentComponent.RectTransform,
812 { RelativeOffset = new Vector2(0.01f, 0.005f) }, style:
"SaveButton", color: Color.Magenta)
814 ToolTip =
"DEBUG ONLY: copy the character info XML to clipboard",
815 OnClicked = (button, o) =>
817 XElement element = info.Save(
null);
818 Clipboard.SetText(element.ToString());
824 parentComponent.RectTransform,
826 { RelativeOffset = new Vector2(0.01f, 0.005f) }, style:
"RandomizeButton")
828 OnClicked = (button, o) =>
830 var headPreset = info.Prefab.Heads.GetRandom(Rand.RandSync.Unsynced);
831 info.Head =
new HeadInfo(info, headPreset);
832 info.SetAttachments(Rand.RandSync.Unsynced);
833 info.SetColors(Rand.RandSync.Unsynced);
838 attachmentSliders.ForEach(s =>
OnSliderMoved?.Invoke(s, s.BarScroll));
843 listBox.ForceLayoutRecalculation();
844 foreach (var childLayoutGroup
in listBox.Content.GetAllChildren<GUILayoutGroup>())
846 childLayoutGroup.Recalculate();
850 private bool OpenHeadSelection(GUIButton button,
object userData)
852 Identifier selectedCategory = (Identifier)userData;
856 if (info.HeadSprite ==
null)
858 DebugConsole.ThrowError($
"Head Selection: the head sprite is null! Failed to open the head selection.");
862 float characterHeightWidthRatio = info.HeadSprite.size.Y / info.HeadSprite.size.X;
863 HeadSelectionList ??=
new GUIListBox(
865 new Point(parentComponent.Rect.Width,
866 (
int)(parentComponent.Rect.Width * characterHeightWidthRatio * 0.6f)), GUI.Canvas)
868 AbsoluteOffset = new Point(parentComponent.Rect.Right - parentComponent.Rect.Width,
871 HeadSelectionList.
Visible =
true;
875 parentComponent.RectTransform.SizeChanged += () =>
877 if (parentComponent ==
null || HeadSelectionList?.RectTransform ==
null || button ==
null)
883 (
int)(parentComponent.Rect.Width * characterHeightWidthRatio * 0.6f)));
885 new Point(parentComponent.Rect.Right - parentComponent.Rect.Width, button.Rect.Bottom);
890 style:
"OuterGlow", color: Color.Black)
892 UserData =
"outerglow",
896 GUILayoutGroup row =
null;
899 ContentXElement headElement = info.Ragdoll.MainElement?.Elements().FirstOrDefault(e =>
900 e.GetAttributeString(
"type",
"").Equals(
"head", StringComparison.OrdinalIgnoreCase));
901 if (headElement ==
null)
903 DebugConsole.ThrowError($
"Head Selection: the head element is null in {info.ragdoll.FileName}! Failed to open the head selection.");
906 ContentXElement headSpriteElement = headElement.GetChildElement(
"sprite");
907 ContentPath spritePathWithTags = headSpriteElement.GetAttributeContentPath(
"texture");
909 var characterConfigElement = info.CharacterConfigElement;
911 var heads = info.Prefab.Heads;
916 foreach (var head
in heads.Where(h => h.TagSet.Contains(selectedCategory)))
918 string spritePath = info.Prefab.ReplaceVars(spritePathWithTags.Value, head);
920 if (!File.Exists(spritePath)) {
continue; }
922 Sprite headSprite =
new Sprite(headSpriteElement,
"", spritePath);
923 headSprite.SourceRect =
925 headSprite.SourceRect.Size);
926 characterSprites.Add(headSprite);
928 if (itemsInRow >= 4 || row ==
null)
930 row =
new GUILayoutGroup(
934 UserData = head.MenuCategory,
940 var btn =
new GUIButton(
new RectTransform(
new Vector2(0.25f, 1.0f), row.RectTransform),
941 style:
"ListBoxElementSquare")
943 OutlineColor = Color.White * 0.5f,
944 PressedColor = Color.White * 0.5f,
946 OnClicked = SwitchHead,
947 Selected = info.Head.Preset == head,
951 new GUIImage(
new RectTransform(Vector2.One, btn.RectTransform), headSprite, scaleToFit:
true);
959 private bool SwitchHead(GUIButton button,
object obj)
962 var headPreset = obj as HeadPreset;
963 if (info.Head.Preset != headPreset)
965 info.Head =
new HeadInfo(info, headPreset, info.Head.HairIndex, info.Head.BeardIndex, info.Head.MoustacheIndex, info.Head.FaceAttachmentIndex)
967 SkinColor = info.Head.SkinColor,
968 HairColor = info.Head.HairColor,
969 FacialHairColor = info.Head.FacialHairColor
971 info.ReloadHeadAttachments();
974 RecreateFrameContents();
975 OnHeadSwitch?.Invoke(
this);
979 private bool SwitchAttachment(GUIScrollBar scrollBar,
WearableType type)
982 int index = (int)Math.Round(scrollBar.BarScrollValue);
986 info.Head.BeardIndex = index;
989 info.Head.FaceAttachmentIndex = index;
992 info.Head.HairIndex = index;
995 info.Head.MoustacheIndex = index;
998 DebugConsole.ThrowError($
"Wearable type not implemented: {type}");
1003 OnSliderMoved?.Invoke(scrollBar, scrollBar.BarScroll);
1010 !GUI.IsMouseOn(HeadSelectionList))
1012 HeadSelectionList.
Visible =
false;
1021 private void ClearSprites()
1023 foreach (
Sprite sprite
in characterSprites) { sprite.
Remove(); }
1024 characterSprites.Clear();
1030 if (HeadSelectionList !=
null)
1033 HeadSelectionList =
null;
readonly LocalizedString CauseOfDeathDescription
readonly AfflictionPrefab Affliction
readonly CauseOfDeathType Type
CauseOfDeath CauseOfDeath
float GetSkillLevel(string skillIdentifier)
Item????????? SelectedItem
The primary selected item. It can be any device that character interacts with. This excludes items li...
void AddMessage(string rawText, Color color, bool playSound, Identifier identifier=default, int? value=null, float lifetime=3.0f)
static Character? Controlled
ContentXElement??? FaceAttachment
ContentXElement??? MoustacheElement
ContentXElement??? BeardElement
ContentXElement??? HairElement
Stores information about the Character that is needed between rounds in the menu etc....
void CalculateHeadPosition(Sprite sprite)
void DrawForeground(SpriteBatch spriteBatch)
static CharacterInfo ClientRead(Identifier speciesName, IReadMessage inc, bool requireJobPrefabFound=true)
void CreateIcon(RectTransform rectT)
bool IsDisguisedAsAnother
CharacterInfo(Identifier speciesName, string name="", string originalName="", Either< Job, JobPrefab > jobOrJobPrefab=null, int variant=0, Rand.RandSync randSync=Rand.RandSync.Unsynced, Identifier npcIdentifier=default)
Character Character
Note: Can be null.
void DrawIcon(SpriteBatch spriteBatch, Vector2 screenPos, Vector2 targetAreaSize)
List< WearableSprite >? AttachmentSprites
GUIComponent CreateInfoFrame(GUIFrame frame, bool returnParent, Sprite permissionIcon=null)
const int MaxAdditionalTalentPoints
NPCPersonalityTrait PersonalityTrait
ushort ID
Unique ID given to character infos in MP. Non-persistent. Used by clients to identify which infos are...
void VerifySpriteTagsLoaded()
GUIFrame CreateCharacterFrame(GUIComponent parent, string text, object userData)
void DrawPortrait(SpriteBatch spriteBatch, Vector2 screenPos, Vector2 offset, float targetWidth, bool flip=false, bool evaluateDisguise=false)
void DrawJobIcon(SpriteBatch spriteBatch, Rectangle area, bool evaluateDisguise=false)
void DrawBackground(SpriteBatch spriteBatch)
void LoadHeadAttachments()
static Point CalculateOffset(Sprite sprite, Point offset)
float GetAttributeFloat(string key, float def)
IEnumerable< ContentXElement > GetChildElements(string name)
ContentPath? GetAttributeContentPath(string key)
ContentXElement? GetChildElement(string name)
virtual void ClearChildren()
RectTransform RectTransform
GUIComponent that can be used to render custom content on the UI
override void AddToGUIUpdateList(bool ignoreChildren=false, int order=0)
GUIFrame ContentBackground
A frame drawn behind the content of the listbox
GUIFrame Content
A frame that contains the contents of the listbox. The frame itself is not rendered.
override void ClearChildren()
static GameSession?? GameSession
static GameScreen GameScreen
Effect ThresholdTintEffect
void OnPlayerSkillsChanged()
OwnerAppearance StoredOwnerAppearance
IEnumerable< Skill > GetSkills()
static readonly PrefabCollection< JobPrefab > Prefabs
readonly LocalizedString DisplayName
LocalizedString DisplayName
readonly Identifier Identifier
void Draw(ISpriteBatch spriteBatch, Vector2 pos, float rotate=0.0f, float scale=1.0f, SpriteEffects spriteEffect=SpriteEffects.None)
int ReadRangedInteger(int min, int max)
Microsoft.Xna.Framework.Color ReadColorR8G8B8()
Identifier ReadIdentifier()
void ExtractJobPrefab(IReadOnlyDictionary< Identifier, string > tags)
void ExtractAppearance(CharacterInfo characterInfo, IdCard idCard)
List< WearableSprite > Attachments