예제 #1
0
        public ItemPrefab(XElement element, string filePath, bool allowOverriding)
        {
            FilePath      = filePath;
            ConfigElement = element;

            originalName = element.GetAttributeString("name", "");
            name         = originalName;
            identifier   = element.GetAttributeString("identifier", "");

            if (!Enum.TryParse(element.GetAttributeString("category", "Misc"), true, out MapEntityCategory category))
            {
                category = MapEntityCategory.Misc;
            }
            Category = category;

            var parentType = element.Parent?.GetAttributeString("itemtype", "") ?? string.Empty;

            //nameidentifier can be used to make multiple items use the same names and descriptions
            string nameIdentifier = element.GetAttributeString("nameidentifier", "");

            //works the same as nameIdentifier, but just replaces the description
            string descriptionIdentifier = element.GetAttributeString("descriptionidentifier", "");

            if (string.IsNullOrEmpty(originalName))
            {
                if (string.IsNullOrEmpty(nameIdentifier))
                {
                    name = TextManager.Get("EntityName." + identifier, true) ?? string.Empty;
                }
                else
                {
                    name = TextManager.Get("EntityName." + nameIdentifier, true) ?? string.Empty;
                }
            }
            else if (Category.HasFlag(MapEntityCategory.Legacy))
            {
                // Legacy items use names as identifiers, so we have to define them in the xml. But we also want to support the translations. Therefore
                if (string.IsNullOrEmpty(nameIdentifier))
                {
                    name = TextManager.Get("EntityName." + identifier, true) ?? originalName;
                }
                else
                {
                    name = TextManager.Get("EntityName." + nameIdentifier, true) ?? originalName;
                }

                if (string.IsNullOrWhiteSpace(identifier))
                {
                    identifier = GenerateLegacyIdentifier(originalName);
                }
            }

            if (string.Equals(parentType, "wrecked", StringComparison.OrdinalIgnoreCase))
            {
                if (!string.IsNullOrEmpty(name))
                {
                    name = TextManager.GetWithVariable("wreckeditemformat", "[name]", name);
                }
            }

            if (string.IsNullOrEmpty(name))
            {
                DebugConsole.ThrowError($"Unnamed item ({identifier})in {filePath}!");
            }

            DebugConsole.Log("    " + name);

            Aliases = new HashSet <string>
                          (element.GetAttributeStringArray("aliases", null, convertToLowerInvariant: true) ??
                          element.GetAttributeStringArray("Aliases", new string[0], convertToLowerInvariant: true));
            Aliases.Add(originalName.ToLowerInvariant());

            Triggers           = new List <Rectangle>();
            DeconstructItems   = new List <DeconstructItem>();
            FabricationRecipes = new List <FabricationRecipe>();
            DeconstructTime    = 1.0f;

            Tags = new HashSet <string>(element.GetAttributeStringArray("tags", new string[0], convertToLowerInvariant: true));
            if (!Tags.Any())
            {
                Tags = new HashSet <string>(element.GetAttributeStringArray("Tags", new string[0], convertToLowerInvariant: true));
            }

            if (element.Attribute("cargocontainername") != null)
            {
                DebugConsole.ThrowError("Error in item prefab \"" + name + "\" - cargo container should be configured using the item's identifier, not the name.");
            }

            SerializableProperty.DeserializeProperties(this, element);

            if (string.IsNullOrEmpty(Description))
            {
                if (!string.IsNullOrEmpty(descriptionIdentifier))
                {
                    Description = TextManager.Get("EntityDescription." + descriptionIdentifier, true) ?? string.Empty;
                }
                else if (string.IsNullOrEmpty(nameIdentifier))
                {
                    Description = TextManager.Get("EntityDescription." + identifier, true) ?? string.Empty;
                }
                else
                {
                    Description = TextManager.Get("EntityDescription." + nameIdentifier, true) ?? string.Empty;
                }
            }

            foreach (XElement subElement in element.Elements())
            {
                switch (subElement.Name.ToString().ToLowerInvariant())
                {
                case "sprite":
                    string spriteFolder = "";
                    if (!subElement.GetAttributeString("texture", "").Contains("/"))
                    {
                        spriteFolder = Path.GetDirectoryName(filePath);
                    }

                    CanSpriteFlipX = subElement.GetAttributeBool("canflipx", true);
                    CanSpriteFlipY = subElement.GetAttributeBool("canflipy", true);

                    sprite = new Sprite(subElement, spriteFolder, lazyLoad: true);
                    if (subElement.Attribute("sourcerect") == null)
                    {
                        DebugConsole.ThrowError("Warning - sprite sourcerect not configured for item \"" + Name + "\"!");
                    }
                    size = sprite.size;

                    if (subElement.Attribute("name") == null && !string.IsNullOrWhiteSpace(Name))
                    {
                        sprite.Name = Name;
                    }
                    sprite.EntityID = identifier;
                    break;

                case "price":
                    if (locationPrices == null)
                    {
                        locationPrices = new Dictionary <string, PriceInfo>();
                    }
                    if (subElement.Attribute("baseprice") != null)
                    {
                        foreach (Tuple <string, PriceInfo> priceInfo in PriceInfo.CreatePriceInfos(subElement, out defaultPrice))
                        {
                            if (priceInfo == null)
                            {
                                continue;
                            }
                            locationPrices.Add(priceInfo.Item1, priceInfo.Item2);
                        }
                    }
                    else if (subElement.Attribute("buyprice") != null)
                    {
                        string locationType = subElement.GetAttributeString("locationtype", "").ToLowerInvariant();
                        locationPrices.Add(locationType, new PriceInfo(subElement));
                    }
                    break;

                case "upgradeoverride":
                {
#if CLIENT
                    var sprites = new List <DecorativeSprite>();
                    foreach (XElement decorSprite in subElement.Elements())
                    {
                        if (decorSprite.Name.ToString().Equals("decorativesprite", StringComparison.OrdinalIgnoreCase))
                        {
                            sprites.Add(new DecorativeSprite(decorSprite));
                        }
                    }
                    UpgradeOverrideSprites.Add(subElement.GetAttributeString("identifier", ""), sprites);
#endif
                    break;
                }

#if CLIENT
                case "inventoryicon":
                {
                    string iconFolder = "";
                    if (!subElement.GetAttributeString("texture", "").Contains("/"))
                    {
                        iconFolder = Path.GetDirectoryName(filePath);
                    }
                    InventoryIcon = new Sprite(subElement, iconFolder, lazyLoad: true);
                }
                break;

                case "minimapicon":
                {
                    string iconFolder = "";
                    if (!subElement.GetAttributeString("texture", "").Contains("/"))
                    {
                        iconFolder = Path.GetDirectoryName(filePath);
                    }
                    MinimapIcon = new Sprite(subElement, iconFolder, lazyLoad: true);
                }
                break;

                case "brokensprite":
                    string brokenSpriteFolder = "";
                    if (!subElement.GetAttributeString("texture", "").Contains("/"))
                    {
                        brokenSpriteFolder = Path.GetDirectoryName(filePath);
                    }

                    var brokenSprite = new BrokenItemSprite(
                        new Sprite(subElement, brokenSpriteFolder, lazyLoad: true),
                        subElement.GetAttributeFloat("maxcondition", 0.0f),
                        subElement.GetAttributeBool("fadein", false),
                        subElement.GetAttributePoint("offset", Point.Zero));

                    int spriteIndex = 0;
                    for (int i = 0; i < BrokenSprites.Count && BrokenSprites[i].MaxCondition < brokenSprite.MaxCondition; i++)
                    {
                        spriteIndex = i;
                    }
                    BrokenSprites.Insert(spriteIndex, brokenSprite);
                    break;

                case "decorativesprite":
                    string decorativeSpriteFolder = "";
                    if (!subElement.GetAttributeString("texture", "").Contains("/"))
                    {
                        decorativeSpriteFolder = Path.GetDirectoryName(filePath);
                    }

                    int groupID = 0;
                    DecorativeSprite decorativeSprite = null;
                    if (subElement.Attribute("texture") == null)
                    {
                        groupID = subElement.GetAttributeInt("randomgroupid", 0);
                    }
                    else
                    {
                        decorativeSprite = new DecorativeSprite(subElement, decorativeSpriteFolder, lazyLoad: true);
                        DecorativeSprites.Add(decorativeSprite);
                        groupID = decorativeSprite.RandomGroupID;
                    }
                    if (!DecorativeSpriteGroups.ContainsKey(groupID))
                    {
                        DecorativeSpriteGroups.Add(groupID, new List <DecorativeSprite>());
                    }
                    DecorativeSpriteGroups[groupID].Add(decorativeSprite);

                    break;

                case "containedsprite":
                    string containedSpriteFolder = "";
                    if (!subElement.GetAttributeString("texture", "").Contains("/"))
                    {
                        containedSpriteFolder = Path.GetDirectoryName(filePath);
                    }
                    var containedSprite = new ContainedItemSprite(subElement, containedSpriteFolder, lazyLoad: true);
                    if (containedSprite.Sprite != null)
                    {
                        ContainedSprites.Add(containedSprite);
                    }
                    break;
#endif
                case "deconstruct":
                    DeconstructTime  = subElement.GetAttributeFloat("time", 1.0f);
                    AllowDeconstruct = true;
                    foreach (XElement deconstructItem in subElement.Elements())
                    {
                        if (deconstructItem.Attribute("name") != null)
                        {
                            DebugConsole.ThrowError("Error in item config \"" + Name + "\" - use item identifiers instead of names to configure the deconstruct items.");
                            continue;
                        }

                        DeconstructItems.Add(new DeconstructItem(deconstructItem));
                    }

                    break;

                case "fabricate":
                case "fabricable":
                case "fabricableitem":
                    fabricationRecipeElements.Add(subElement);
                    break;

                case "preferredcontainer":
                    var preferredContainer = new PreferredContainer(subElement);
                    if (preferredContainer.Primary.Count == 0 && preferredContainer.Secondary.Count == 0)
                    {
                        DebugConsole.ThrowError($"Error in item prefab {Name}: preferred container has no preferences defined ({subElement.ToString()}).");
                    }
                    else
                    {
                        PreferredContainers.Add(preferredContainer);
                    }
                    break;

                case "trigger":
                    Rectangle trigger = new Rectangle(0, 0, 10, 10)
                    {
                        X      = subElement.GetAttributeInt("x", 0),
                        Y      = subElement.GetAttributeInt("y", 0),
                        Width  = subElement.GetAttributeInt("width", 0),
                        Height = subElement.GetAttributeInt("height", 0)
                    };

                    Triggers.Add(trigger);

                    break;

                case "levelresource":
                    foreach (XElement levelCommonnessElement in subElement.Elements())
                    {
                        string levelName = levelCommonnessElement.GetAttributeString("levelname", "").ToLowerInvariant();
                        if (!LevelCommonness.ContainsKey(levelName))
                        {
                            LevelCommonness.Add(levelName, levelCommonnessElement.GetAttributeFloat("commonness", 0.0f));
                        }
                    }
                    break;

                case "suitabletreatment":
                    if (subElement.Attribute("name") != null)
                    {
                        DebugConsole.ThrowError("Error in item prefab \"" + Name + "\" - suitable treatments should be defined using item identifiers, not item names.");
                    }

                    string treatmentIdentifier = subElement.GetAttributeString("identifier", "").ToLowerInvariant();

                    float suitability = subElement.GetAttributeFloat("suitability", 0.0f);

                    treatmentSuitability.Add(treatmentIdentifier, suitability);
                    break;
                }
            }

            // Set the default price in case the prices are defined in the old way
            // with separate Price elements and there is no default price explicitly set
            if (locationPrices != null && locationPrices.Any())
            {
                defaultPrice ??= new PriceInfo(GetMinPrice() ?? 0, false);
            }

            if (sprite == null)
            {
                DebugConsole.ThrowError("Item \"" + Name + "\" has no sprite!");
#if SERVER
                sprite            = new Sprite("", Vector2.Zero);
                sprite.SourceRect = new Rectangle(0, 0, 32, 32);
#else
                sprite = new Sprite(TextureLoader.PlaceHolderTexture, null, null)
                {
                    Origin = TextureLoader.PlaceHolderTexture.Bounds.Size.ToVector2() / 2
                };
#endif
                size            = sprite.size;
                sprite.EntityID = identifier;
            }

            if (string.IsNullOrEmpty(identifier))
            {
                DebugConsole.ThrowError(
                    "Item prefab \"" + name + "\" has no identifier. All item prefabs have a unique identifier string that's used to differentiate between items during saving and loading.");
            }

            AllowedLinks = element.GetAttributeStringArray("allowedlinks", new string[0], convertToLowerInvariant: true).ToList();

            Prefabs.Add(this, allowOverriding);
        }
예제 #2
0
        private void CreateItemFrame(PurchasedItem pi, PriceInfo priceInfo, GUIListBox listBox, int width)
        {
            GUIFrame frame = new GUIFrame(new RectTransform(new Point(listBox.Content.Rect.Width, (int)(GUI.Scale * 50)), listBox.Content.RectTransform), style: "ListBoxElement")
            {
                UserData = pi,
                ToolTip  = pi.ItemPrefab.Description
            };

            var content = new GUILayoutGroup(new RectTransform(Vector2.One, frame.RectTransform), isHorizontal: true)
            {
                RelativeSpacing = 0.02f,
                Stretch         = true
            };

            ScalableFont font = listBox.Rect.Width < 280 ? GUI.SmallFont : GUI.Font;

            Sprite itemIcon = pi.ItemPrefab.InventoryIcon ?? pi.ItemPrefab.sprite;

            if (itemIcon != null)
            {
                GUIImage img = new GUIImage(new RectTransform(new Point((int)(content.Rect.Height * 0.8f)), content.RectTransform, Anchor.CenterLeft), itemIcon, scaleToFit: true)
                {
                    Color = itemIcon == pi.ItemPrefab.InventoryIcon ? pi.ItemPrefab.InventoryIconColor : pi.ItemPrefab.SpriteColor
                };
                img.RectTransform.MaxSize = img.Rect.Size;
                //img.Scale = Math.Min(Math.Min(40.0f / img.SourceRect.Width, 40.0f / img.SourceRect.Height), 1.0f);
            }

            GUITextBlock textBlock = new GUITextBlock(new RectTransform(new Vector2(0.6f, 1.0f), content.RectTransform),
                                                      pi.ItemPrefab.Name, font: font)
            {
                ToolTip = pi.ItemPrefab.Description
            };

            new GUITextBlock(new RectTransform(new Vector2(0.2f, 1.0f), content.RectTransform),
                             priceInfo.BuyPrice.ToString(), font: font, textAlignment: Alignment.CenterRight)
            {
                ToolTip = pi.ItemPrefab.Description
            };

            //If its the store menu, quantity will always be 0
            GUINumberInput amountInput = null;

            if (pi.Quantity > 0)
            {
                amountInput = new GUINumberInput(new RectTransform(new Vector2(0.3f, 1.0f), content.RectTransform),
                                                 GUINumberInput.NumberType.Int)
                {
                    MinValueInt = 0,
                    MaxValueInt = 100,
                    UserData    = pi,
                    IntValue    = pi.Quantity
                };
                amountInput.OnValueChanged += (numberInput) =>
                {
                    PurchasedItem purchasedItem = numberInput.UserData as PurchasedItem;

                    //Attempting to buy
                    if (numberInput.IntValue > purchasedItem.Quantity)
                    {
                        int quantity = numberInput.IntValue - purchasedItem.Quantity;
                        //Cap the numberbox based on the amount we can afford.
                        quantity = Campaign.Money <= 0 ?
                                   0 : Math.Min((int)(Campaign.Money / (float)priceInfo.BuyPrice), quantity);
                        for (int i = 0; i < quantity; i++)
                        {
                            BuyItem(numberInput, purchasedItem);
                        }
                        numberInput.IntValue = purchasedItem.Quantity;
                    }
                    //Attempting to sell
                    else
                    {
                        int quantity = purchasedItem.Quantity - numberInput.IntValue;
                        for (int i = 0; i < quantity; i++)
                        {
                            SellItem(numberInput, purchasedItem);
                        }
                    }
                };
            }
            listBox.RecalculateChildren();
            content.Recalculate();
            content.RectTransform.RecalculateChildren(true, true);
            amountInput?.LayoutGroup.Recalculate();
            textBlock.Text = ToolBox.LimitString(textBlock.Text, textBlock.Font, textBlock.Rect.Width);
        }
예제 #3
0
        public static List <Tuple <string, PriceInfo> > CreatePriceInfos(XElement element, out PriceInfo defaultPrice)
        {
            defaultPrice = null;
            var basePrice     = element.GetAttributeInt("baseprice", 0);
            var soldByDefault = element.GetAttributeBool("soldbydefault", true);
            var minAmount     = GetMinAmount(element);
            var maxAmount     = GetMaxAmount(element);
            var canBeSpecial  = element.GetAttributeBool("canbespecial", true);
            var priceInfos    = new List <Tuple <string, PriceInfo> >();

            foreach (XElement childElement in element.GetChildElements("price"))
            {
                var priceMultiplier = childElement.GetAttributeFloat("multiplier", 1.0f);
                var sold            = childElement.GetAttributeBool("sold", soldByDefault);
                priceInfos.Add(new Tuple <string, PriceInfo>(childElement.GetAttributeString("locationtype", "").ToLowerInvariant(),
                                                             new PriceInfo(price: (int)(priceMultiplier * basePrice), canBeBought: sold,
                                                                           minAmount: sold ? GetMinAmount(childElement, minAmount) : 0,
                                                                           maxAmount: sold ? GetMaxAmount(childElement, maxAmount) : 0,
                                                                           canBeSpecial: canBeSpecial)));
            }

            var canBeBoughtAtOtherLocations = soldByDefault && element.GetAttributeBool("soldeverywhere", true);

            defaultPrice = new PriceInfo(basePrice, canBeBoughtAtOtherLocations,
                                         minAmount: canBeBoughtAtOtherLocations ? minAmount : 0,
                                         maxAmount: canBeBoughtAtOtherLocations ? maxAmount : 0,
                                         canBeSpecial: canBeSpecial);

            return(priceInfos);
        }
예제 #4
0
        private void UpdateLocationView(Location location)
        {
            if (location == null)
            {
                string errorMsg = "Failed to update CampaignUI location view (location was null)\n" + Environment.StackTrace;
                DebugConsole.ThrowError(errorMsg);
                GameAnalyticsManager.AddErrorEventOnce("CampaignUI.UpdateLocationView:LocationNull", GameAnalyticsSDK.Net.EGAErrorSeverity.Error, errorMsg);
                return;
            }

            if (characterPreviewFrame != null)
            {
                characterPreviewFrame.Parent.RemoveChild(characterPreviewFrame);
                characterPreviewFrame = null;
            }

            if (Campaign is SinglePlayerCampaign)
            {
                var hireableCharacters = location.GetHireableCharacters();
                foreach (GUIComponent child in characterList.Content.Children.ToList())
                {
                    if (child.UserData is CharacterInfo character)
                    {
                        if (GameMain.GameSession.CrewManager.GetCharacterInfos().Contains(character))
                        {
                            continue;
                        }
                    }
                    else if (child.UserData as string == "mycrew" || child.UserData as string == "hire")
                    {
                        continue;
                    }
                    characterList.RemoveChild(child);
                }
                if (!hireableCharacters.Any())
                {
                    new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.2f), characterList.Content.RectTransform), TextManager.Get("HireUnavailable"), textAlignment: Alignment.Center)
                    {
                        CanBeFocused = false
                    };
                }
                else
                {
                    foreach (CharacterInfo c in hireableCharacters)
                    {
                        var frame = c.CreateCharacterFrame(characterList.Content, c.Name + " (" + c.Job.Name + ")", c);
                        new GUITextBlock(new RectTransform(Vector2.One, frame.RectTransform, Anchor.TopRight), c.Salary.ToString(), textAlignment: Alignment.CenterRight);
                    }
                }
            }
            characterList.UpdateScrollBarSize();

            RefreshMyItems();

            bool purchaseableItemsFound = false;

            foreach (MapEntityPrefab mapEntityPrefab in MapEntityPrefab.List)
            {
                if (!(mapEntityPrefab is ItemPrefab itemPrefab))
                {
                    continue;
                }

                PriceInfo priceInfo = itemPrefab.GetPrice(Campaign.Map.CurrentLocation);
                if (priceInfo != null)
                {
                    purchaseableItemsFound = true; break;
                }
            }

            //disable store tab if there's nothing to buy
            tabButtons.Find(btn => (Tab)btn.UserData == Tab.Store).Enabled = purchaseableItemsFound;

            if (selectedTab == Tab.Store && !purchaseableItemsFound)
            {
                //switch out from store tab if there's nothing to buy
                SelectTab(Tab.Map);
            }
            else
            {
                //refresh store view
                FillStoreItemList();
                FilterStoreItems(MapEntityCategory.Equipment, searchBox.Text);
            }
        }
예제 #5
0
        private void CreateItemFrame(PurchasedItem pi, PriceInfo priceInfo, GUIListBox listBox, int width)
        {
            GUIFrame frame = new GUIFrame(new RectTransform(new Point(listBox.Rect.Width, 50), listBox.Content.RectTransform), style: "ListBoxElement")
            {
                UserData = pi,
                ToolTip  = pi.ItemPrefab.Description
            };

            ScalableFont font = listBox.Rect.Width < 280 ? GUI.SmallFont : GUI.Font;

            GUITextBlock textBlock = new GUITextBlock(new RectTransform(new Point(listBox.Rect.Width - (pi.Quantity > 0 ? 160 : 120), 25), frame.RectTransform, Anchor.CenterLeft)
            {
                AbsoluteOffset = new Point(40, 0),
            }, pi.ItemPrefab.Name, font: font)
            {
                ToolTip = pi.ItemPrefab.Description
            };

            textBlock.Text = ToolBox.LimitString(textBlock.Text, textBlock.Font, textBlock.Rect.Width);

            Sprite itemIcon = pi.ItemPrefab.InventoryIcon ?? pi.ItemPrefab.sprite;

            if (itemIcon != null)
            {
                GUIImage img = new GUIImage(new RectTransform(new Point(40, 40), frame.RectTransform, Anchor.CenterLeft), itemIcon)
                {
                    Color = itemIcon == pi.ItemPrefab.InventoryIcon ? pi.ItemPrefab.InventoryIconColor : pi.ItemPrefab.SpriteColor
                };
                img.Scale = Math.Min(Math.Min(40.0f / img.SourceRect.Width, 40.0f / img.SourceRect.Height), 1.0f);
            }

            textBlock = new GUITextBlock(new RectTransform(new Point(60, 25), frame.RectTransform, Anchor.CenterRight)
            {
                AbsoluteOffset = new Point(pi.Quantity > 0 ? 70 : 25, 0)
            },
                                         priceInfo.BuyPrice.ToString(), font: font, textAlignment: Alignment.CenterRight)
            {
                ToolTip = pi.ItemPrefab.Description
            };

            //If its the store menu, quantity will always be 0
            if (pi.Quantity > 0)
            {
                var amountInput = new GUINumberInput(new RectTransform(new Point(50, 40), frame.RectTransform, Anchor.CenterRight)
                {
                    AbsoluteOffset = new Point(20, 0)
                },
                                                     GUINumberInput.NumberType.Int)
                {
                    MinValueInt = 0,
                    MaxValueInt = 1000,
                    UserData    = pi,
                    IntValue    = pi.Quantity
                };
                amountInput.OnValueChanged += (numberInput) =>
                {
                    PurchasedItem purchasedItem = numberInput.UserData as PurchasedItem;

                    //Attempting to buy
                    if (numberInput.IntValue > purchasedItem.Quantity)
                    {
                        int quantity = numberInput.IntValue - purchasedItem.Quantity;
                        //Cap the numberbox based on the amount we can afford.
                        quantity = Campaign.Money <= 0 ?
                                   0 : Math.Min((int)(Campaign.Money / (float)priceInfo.BuyPrice), quantity);
                        for (int i = 0; i < quantity; i++)
                        {
                            BuyItem(numberInput, purchasedItem);
                        }
                        numberInput.IntValue = purchasedItem.Quantity;
                    }
                    //Attempting to sell
                    else
                    {
                        int quantity = purchasedItem.Quantity - numberInput.IntValue;
                        for (int i = 0; i < quantity; i++)
                        {
                            SellItem(numberInput, purchasedItem);
                        }
                    }
                };
            }
        }