private void FindCreateUnit(string effectId, AbilityTalentBase abilityTalentBase)
        {
            if (abilityTalentBase == null)
            {
                throw new ArgumentNullException(nameof(abilityTalentBase));
            }

            if (!string.IsNullOrEmpty(effectId))
            {
                // find CEffectCreateUnit
                XElement effectCreateUnitElement = GameData.MergeXmlElements(GameData.Elements("CEffectCreateUnit").Where(x => x.Attribute("id")?.Value == effectId), false);
                if (effectCreateUnitElement != null)
                {
                    string spawnUnitValue = effectCreateUnitElement.Element("SpawnUnit")?.Attribute("value")?.Value;
                    if (!string.IsNullOrEmpty(spawnUnitValue))
                    {
                        if (GameData.Elements("CUnit").Where(x => x.Attribute("id")?.Value == spawnUnitValue).Any())
                        {
                            abilityTalentBase.AddCreatedUnit(spawnUnitValue);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Sets the ability data.
        /// </summary>
        /// <param name="abilityElement">The ability element.</param>
        /// <param name="abilityTalentBase"></param>
        /// <param name="index"></param>
        protected void SetAbilityTalentData(XElement abilityElement, AbilityTalentBase abilityTalentBase, string index)
        {
            if (abilityElement == null)
            {
                throw new ArgumentNullException(nameof(abilityElement));
            }
            if (abilityTalentBase == null)
            {
                throw new ArgumentNullException(nameof(abilityTalentBase));
            }

            // parent lookup
            string parentValue = abilityElement.Attribute("parent")?.Value;

            if (!string.IsNullOrEmpty(parentValue))
            {
                XElement parentElement = GameData.MergeXmlElements(GameData.Elements(abilityElement.Name.LocalName).Where(x => x.Attribute("id")?.Value == parentValue));
                if (parentElement != null)
                {
                    SetAbilityTalentData(parentElement, abilityTalentBase, index);
                }
            }

            // don't want these
            if (parentValue == "attack" || abilityElement.Name.LocalName == "CAbilAttack")
            {
                abilityTalentBase.AbilityTalentId.ReferenceId = string.Empty;
            }

            Action setCmdButtonArrayDataAction = null;

            // look through all elements to set all the data
            foreach (XElement element in abilityElement.Elements())
            {
                string elementName = element.Name.LocalName.ToUpper();

                if (elementName == "COST")
                {
                    SetCostData(element, abilityTalentBase);
                }
                else if (elementName == "EFFECT")
                {
                    SetEffectData(element, abilityTalentBase);
                }
                else if (elementName == "CMDBUTTONARRAY")
                {
                    string indexValue = element.Attribute("index")?.Value;

                    if (!string.IsNullOrEmpty(index) && index == indexValue)
                    {
                        setCmdButtonArrayDataAction = () => SetCmdButtonArrayData(element, abilityTalentBase);
                    }
                    else
                    {
                        // only set if index is execute
                        // cancel is also an available index, but it doesn't seem to be used in HOTS
                        if (indexValue.Equals("Execute", StringComparison.OrdinalIgnoreCase))
                        {
                            setCmdButtonArrayDataAction = () => SetCmdButtonArrayData(element, abilityTalentBase);
                        }
                    }
                }
                else if (elementName == "PRODUCEDUNITARRAY")
                {
                    string elementValue = element.Attribute("value")?.Value;

                    if (!string.IsNullOrEmpty(elementValue))
                    {
                        if (GameData.Elements("CUnit").Where(x => x.Attribute("id")?.Value == elementValue).Any())
                        {
                            abilityTalentBase.AddCreatedUnit(elementValue);
                        }
                    }
                }
                else if (elementName == "NAME") // ability name
                {
                    if (string.IsNullOrEmpty(abilityTalentBase.Name) && GameData.TryGetGameString(element.Attribute("value")?.Value, out string value))
                    {
                        abilityTalentBase.Name = value;
                    }
                }
                else if (elementName == "PARENTABIL")
                {
                    string parentAbility = element.Attribute("value")?.Value;
                    if (!string.IsNullOrEmpty(parentAbility))
                    {
                        XElement parentAbilityElement = GetAbilityElements(parentAbility).FirstOrDefault();
                        if (parentAbilityElement != null)
                        {
                            string defaultButtonFace = parentAbilityElement.Element("CmdButtonArray")?.Attribute("DefaultButtonFace")?.Value;

                            abilityTalentBase.ParentLink = new AbilityTalentId(parentAbility, defaultButtonFace);
                        }
                    }
                }
            }

            // must execute the cmdButtonArrayData last
            setCmdButtonArrayDataAction?.Invoke();
        }