public bool CanBeFixed(Character character) { if (character == null) { return(false); } bool success = true; foreach (string itemName in requiredItems) { Item item = character.Inventory.FindItem(itemName); bool itemFound = (item != null); if (!itemFound) { success = false; } } foreach (Skill skill in requiredSkills) { float characterSkill = character.GetSkillLevel(skill.Name); bool sufficientSkill = characterSkill >= skill.Level; if (!sufficientSkill) { success = false; } } return(success); }
public bool CanBeFixed(Character character, GUIComponent reqFrame = null) { if (character == null) { return(false); } bool success = true; foreach (string itemName in requiredItems) { Item item = character.Inventory.FindItem(itemName); bool itemFound = (item != null); if (!itemFound) { success = false; } if (reqFrame != null) { GUIComponent component = reqFrame.children.Find(c => c.UserData as string == itemName); GUITextBlock text = component as GUITextBlock; if (text != null) { text.TextColor = itemFound ? Color.LightGreen : Color.Red; } } } foreach (Skill skill in requiredSkills) { float characterSkill = character.GetSkillLevel(skill.Name); bool sufficientSkill = characterSkill >= skill.Level; if (!sufficientSkill) { success = false; } if (reqFrame != null) { GUIComponent component = reqFrame.children.Find(c => c.UserData as Skill == skill); GUITextBlock text = component as GUITextBlock; if (text != null) { text.TextColor = sufficientSkill ? Color.LightGreen : Color.Red; } } } return(success); }
public GUIComponent CreateInfoFrame(GUIFrame frame, bool returnParent, Sprite permissionIcon = null) { var paddedFrame = new GUILayoutGroup(new RectTransform(new Vector2(0.874f, 0.58f), frame.RectTransform, Anchor.TopCenter) { RelativeOffset = new Vector2(0.0f, 0.05f) }) { RelativeSpacing = 0.05f //Stretch = true }; var headerArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.322f), paddedFrame.RectTransform), isHorizontal: true); new GUICustomComponent(new RectTransform(new Vector2(0.425f, 1.0f), headerArea.RectTransform), onDraw: (sb, component) => DrawInfoFrameCharacterIcon(sb, component.Rect)); ScalableFont font = paddedFrame.Rect.Width < 280 ? GUI.SmallFont : GUI.Font; var headerTextArea = new GUILayoutGroup(new RectTransform(new Vector2(0.575f, 1.0f), headerArea.RectTransform)) { RelativeSpacing = 0.02f, Stretch = true }; Color?nameColor = null; if (Job != null) { nameColor = Job.Prefab.UIColor; } GUITextBlock characterNameBlock = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform), ToolBox.LimitString(Name, GUI.Font, headerTextArea.Rect.Width), textColor: nameColor, font: GUI.Font) { ForceUpperCase = true, Padding = Vector4.Zero }; if (permissionIcon != null) { Point iconSize = permissionIcon.SourceRect.Size; int iconWidth = (int)((float)characterNameBlock.Rect.Height / iconSize.Y * iconSize.X); new GUIImage(new RectTransform(new Point(iconWidth, characterNameBlock.Rect.Height), characterNameBlock.RectTransform) { AbsoluteOffset = new Point(-iconWidth - 2, 0) }, permissionIcon) { IgnoreLayoutGroups = true }; } if (Job != null) { new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform), Job.Name, textColor: Job.Prefab.UIColor, font: font) { Padding = Vector4.Zero }; } if (personalityTrait != null) { new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), headerTextArea.RectTransform), TextManager.AddPunctuation(':', TextManager.Get("PersonalityTrait"), TextManager.Get("personalitytrait." + personalityTrait.Name.Replace(" ", ""))), font: font) { Padding = Vector4.Zero }; } if (Job != null && (Character == null || !Character.IsDead)) { var skillsArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.63f), paddedFrame.RectTransform, Anchor.BottomCenter, Pivot.BottomCenter)) { Stretch = true }; var skills = Job.Skills; skills.Sort((s1, s2) => - s1.Level.CompareTo(s2.Level)); new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), skillsArea.RectTransform), TextManager.AddPunctuation(':', TextManager.Get("skills"), string.Empty), font: font) { Padding = Vector4.Zero }; foreach (Skill skill in skills) { Color textColor = Color.White * (0.5f + skill.Level / 200.0f); var skillName = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), skillsArea.RectTransform), TextManager.Get("SkillName." + skill.Identifier), textColor: textColor, font: font) { Padding = Vector4.Zero }; float modifiedSkillLevel = skill.Level; if (Character != null) { modifiedSkillLevel = Character.GetSkillLevel(skill.Identifier); } if (!MathUtils.NearlyEqual(MathF.Round(modifiedSkillLevel), MathF.Round(skill.Level))) { int skillChange = (int)MathF.Round(modifiedSkillLevel - skill.Level); string changeText = $"{(skillChange > 0 ? "+" : "") + skillChange}"; new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), skillName.RectTransform), $"{(int)skill.Level} ({changeText})", textColor: textColor, font: font, textAlignment: Alignment.CenterRight); } else { new GUITextBlock(new RectTransform(new Vector2(1.0f, 1.0f), skillName.RectTransform), ((int)skill.Level).ToString(), textColor: textColor, font: font, textAlignment: Alignment.CenterRight); } } } else if (Character != null && Character.IsDead) { var deadArea = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.63f), paddedFrame.RectTransform, Anchor.BottomCenter, Pivot.BottomCenter)) { Stretch = true }; string deadDescription = TextManager.AddPunctuation(':', TextManager.Get("deceased") + "\n" + Character.CauseOfDeath.Affliction?.CauseOfDeathDescription ?? TextManager.AddPunctuation(':', TextManager.Get("CauseOfDeath"), TextManager.Get("CauseOfDeath." + Character.CauseOfDeath.Type.ToString()))); new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), deadArea.RectTransform), deadDescription, textColor: GUI.Style.Red, font: font, textAlignment: Alignment.TopLeft) { Padding = Vector4.Zero }; } if (returnParent) { return(frame); } else { return(paddedFrame); } }
private void SetDamage(int sectionIndex, float damage, Character attacker = null, bool createNetworkEvent = true) { if (Submarine != null && Submarine.GodMode || Indestructible) { return; } if (!Prefab.Body) { return; } if (!MathUtils.IsValid(damage)) { return; } damage = MathHelper.Clamp(damage, 0.0f, Prefab.Health); #if SERVER if (GameMain.Server != null && createNetworkEvent && damage != Sections[sectionIndex].damage) { GameMain.Server.CreateEntityEvent(this); } bool noGaps = true; for (int i = 0; i < Sections.Length; i++) { if (i != sectionIndex && SectionIsLeaking(i)) { noGaps = false; break; } } #endif if (damage < Prefab.Health * LeakThreshold) { if (Sections[sectionIndex].gap != null) { #if SERVER //the structure doesn't have any other gap, log the structure being fixed if (noGaps && attacker != null) { GameServer.Log((Sections[sectionIndex].gap.IsRoomToRoom ? "Inner" : "Outer") + " wall repaired by " + attacker.Name, ServerLog.MessageType.ItemInteraction); } #endif DebugConsole.Log("Removing gap (ID " + Sections[sectionIndex].gap.ID + ", section: " + sectionIndex + ") from wall " + ID); //remove existing gap if damage is below leak threshold Sections[sectionIndex].gap.Open = 0.0f; Sections[sectionIndex].gap.Remove(); Sections[sectionIndex].gap = null; } } else { if (Sections[sectionIndex].gap == null) { Rectangle gapRect = Sections[sectionIndex].rect; float diffFromCenter; if (IsHorizontal) { diffFromCenter = (gapRect.Center.X - this.rect.Center.X) / (float)this.rect.Width * BodyWidth; if (BodyWidth > 0.0f) { gapRect.Width = (int)(BodyWidth * (gapRect.Width / (float)this.rect.Width)); } if (BodyHeight > 0.0f) { gapRect.Height = (int)BodyHeight; } } else { diffFromCenter = ((gapRect.Y - gapRect.Height / 2) - (this.rect.Y - this.rect.Height / 2)) / (float)this.rect.Height * BodyHeight; if (BodyWidth > 0.0f) { gapRect.Width = (int)BodyWidth; } if (BodyHeight > 0.0f) { gapRect.Height = (int)(BodyHeight * (gapRect.Height / (float)this.rect.Height)); } } if (FlippedX) { diffFromCenter = -diffFromCenter; } if (BodyRotation != 0.0f) { Vector2 structureCenter = Position; Vector2 gapPos = structureCenter + new Vector2( (float)Math.Cos(IsHorizontal ? -BodyRotation : MathHelper.PiOver2 - BodyRotation), (float)Math.Sin(IsHorizontal ? -BodyRotation : MathHelper.PiOver2 - BodyRotation)) * diffFromCenter; gapRect = new Rectangle((int)(gapPos.X - gapRect.Width / 2), (int)(gapPos.Y + gapRect.Height / 2), gapRect.Width, gapRect.Height); } gapRect.X -= 10; gapRect.Y += 10; gapRect.Width += 20; gapRect.Height += 20; bool horizontalGap = !IsHorizontal; if (Prefab.BodyRotation != 0.0f) { //rotation within a 90 deg sector (e.g. 100 -> 10, 190 -> 10, -10 -> 80) float sectorizedRotation = MathUtils.WrapAngleTwoPi(BodyRotation) % MathHelper.PiOver2; //diagonal if 30 < angle < 60 bool diagonal = sectorizedRotation > MathHelper.Pi / 6 && sectorizedRotation < MathHelper.Pi / 3; //gaps on the lower half of a diagonal wall are horizontal, ones on the upper half are vertical if (diagonal) { horizontalGap = gapRect.Y - gapRect.Height / 2 < Position.Y; } } Sections[sectionIndex].gap = new Gap(gapRect, horizontalGap, Submarine); //free the ID, because if we give gaps IDs we have to make sure they always match between the clients and the server and //that clients create them in the correct order along with every other entity created/removed during the round //which COULD be done via entityspawner, but it's unnecessary because we never access these gaps by ID Sections[sectionIndex].gap.FreeID(); Sections[sectionIndex].gap.ShouldBeSaved = false; Sections[sectionIndex].gap.ConnectedWall = this; DebugConsole.Log("Created gap (ID " + Sections[sectionIndex].gap.ID + ", section: " + sectionIndex + ") on wall " + ID); //AdjustKarma(attacker, 300); #if SERVER //the structure didn't have any other gaps yet, log the breach if (noGaps && attacker != null) { GameServer.Log((Sections[sectionIndex].gap.IsRoomToRoom ? "Inner" : "Outer") + " wall breached by " + attacker.Name, ServerLog.MessageType.ItemInteraction); } #endif } float gapOpen = (damage / Prefab.Health - LeakThreshold) * (1.0f / (1.0f - LeakThreshold)); Sections[sectionIndex].gap.Open = gapOpen; } float damageDiff = damage - Sections[sectionIndex].damage; bool hadHole = SectionBodyDisabled(sectionIndex); Sections[sectionIndex].damage = MathHelper.Clamp(damage, 0.0f, Prefab.Health); //otherwise it's possible to infinitely gain karma by welding fixed things if (attacker != null && damageDiff != 0.0f) { AdjustKarma(attacker, damageDiff); #if CLIENT if (GameMain.Client == null) { #endif if (damageDiff < 0.0f) { attacker.Info.IncreaseSkillLevel("mechanical", -damageDiff * SkillIncreaseMultiplier / Math.Max(attacker.GetSkillLevel("mechanical"), 1.0f), SectionPosition(sectionIndex, true)); } #if CLIENT } #endif } bool hasHole = SectionBodyDisabled(sectionIndex); if (hadHole == hasHole) { return; } UpdateSections(); }