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);
        }
예제 #2
0
        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);
        }
예제 #3
0
        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);
            }
        }
예제 #4
0
        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();
        }