Ejemplo n.º 1
0
        /// <summary>
        /// Gets an ability value.
        /// If the stacking rule in the mod is DoNotStack, an arbitrary matching ability will be chosen.
        /// If there are no values, null will be returned.
        /// </summary>
        /// <param name="name">The name of the ability.</param>
        /// <param name="obj">The object from which to get the value.</param>
        /// <param name="index">The ability value index (usually 1 or 2).</param>
        /// <param name="filter">A filter for the abilities. For instance, you might want to filter by the ability grouping rule's value.</param>
        /// <returns>The ability value.</returns>
        public static string GetAbilityValue(this IAbilityObject obj, string name, int index = 1, bool includeShared = true, bool includeEmpireCommon = true, Func <Ability, bool> filter = null)
        {
            if (obj == null)
            {
                return(null);
            }

            var abils = obj.Abilities();

            if (includeShared)
            {
                abils = abils.Union(obj.SharedAbilities());
            }
            if (includeEmpireCommon)
            {
                abils = abils.Union(obj.EmpireCommonAbilities());
            }

            abils = abils.Where(a => a.Rule != null && a.Rule.Matches(name) && a.Rule.CanTarget(obj.AbilityTarget) && (filter == null || filter(a)));
            abils = abils.Stack(obj);
            if (!abils.Any())
            {
                return(null);
            }
            return(abils.First().Values[index - 1]);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// All abilities belonging to an object, before stacking.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="includeShared"></param>
        /// <returns></returns>
        public static IEnumerable <Ability> UnstackedAbilities(this IAbilityObject obj, bool includeShared, Func <IAbilityObject, bool> sourceFilter = null)
        {
            if (obj == null)
            {
                return(Enumerable.Empty <Ability>());
            }

            IEnumerable <Ability> result;

            if (sourceFilter == null || sourceFilter(obj))
            {
                result = obj.IntrinsicAbilities.Concat(obj.DescendantAbilities(sourceFilter)).Concat(obj.AncestorAbilities(sourceFilter));
            }
            else
            {
                result = obj.DescendantAbilities(sourceFilter).Concat(obj.AncestorAbilities(sourceFilter));
            }

            if (includeShared)
            {
                result = result.Concat(obj.SharedAbilities(sourceFilter));
            }

            return(result);
        }
        private void CreateProjectiles(float angleToTarget, AbilityInput input)
        {
            foreach (Muzzle muzzle in Ability.Behaviour.Muzzles)
            {
                IAbilityObject abilityObject = muzzle.Spawner.Spawn(Ability, muzzle.Multiplier);
                abilityObject.GameObject.transform.position = Ability.Owner.transform.position;

                float   angle     = GetAngle(muzzle, angleToTarget);
                Vector2 direction = angle.GetDirection();

                if (Ability.Behaviour.UseOrthographicScaling)
                {
                    direction = Utility.ScaleToOrthographicVector(direction);
                }


                if (abilityObject is ISetTargetDirection directionSetter)
                {
                    directionSetter.SetTargetDirection(direction);
                }

                if (abilityObject is ISetTargetPosition positionSetter)
                {
                    positionSetter.SetTargetPosition(input.TargetPosition);
                }

                if (abilityObject is IPersistentAbilityObject persistentObject)
                {
                    PersistentObjects.Add(persistentObject);
                }
            }
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Gets abilities that have been shared to an object.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static IEnumerable <Ability> SharedAbilities(this IAbilityObject obj, Func <IAbilityObject, bool> sourceFilter = null)
        {
            // Unowned objects cannot have abilities shared to them.
            var ownable = obj as IOwnableAbilityObject;

            if (ownable == null || ownable.Owner == null)
            {
                yield break;
            }

            // update cache if necessary
            foreach (var clause in ownable.Owner.ReceivedTreatyClauses.Flatten().OfType <ShareAbilityClause>())
            {
                var tuple = Tuple.Create(ownable, clause.Owner);
                if (Empire.Current == null || !Galaxy.Current.SharedAbilityCache.ContainsKey(tuple))
                {
                    Galaxy.Current.SharedAbilityCache[tuple] = FindSharedAbilities(ownable, clause).ToArray();
                }
            }

            // get cached abilities
            foreach (var keyTuple in Galaxy.Current.SharedAbilityCache.Keys.Where(k => k.Item1 == ownable && (sourceFilter == null || sourceFilter(k.Item2))))
            {
                foreach (var abil in Galaxy.Current.SharedAbilityCache[keyTuple])
                {
                    yield return(abil);
                }
            }
        }
Ejemplo n.º 5
0
    public IAbilityObject Spawn(Ability ability, float multiplier)
    {
        IAbilityObject abilityObject = Value.Spawn(ability, multiplier);

        HierarchyManager.Add(abilityObject.GameObject, HierarchyCategory.AbilityObjects);

        return(abilityObject);
    }
Ejemplo n.º 6
0
        /// <summary>
        /// Abilities passed up from descendant objects.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="includeShared"></param>
        /// <returns></returns>
        public static IEnumerable <Ability> DescendantAbilities(this IAbilityObject obj, Func <IAbilityObject, bool> sourceFilter = null)
        {
            var abils = new List <Ability>();

            foreach (var c in obj.Descendants(sourceFilter))
            {
                abils.AddRange(c.IntrinsicAbilities);
            }
            return(abils.Where(a => a.Rule == null || a.Rule.CanTarget(obj.AbilityTarget)));
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Abilities inherited from ancestor objects.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="includeShared"></param>
        /// <returns></returns>
        public static IEnumerable <Ability> AncestorAbilities(this IAbilityObject obj, Func <IAbilityObject, bool> sourceFilter = null)
        {
            var abils = new List <Ability>();

            foreach (var p in obj.Ancestors(sourceFilter).ExceptSingle(null))
            {
                abils.AddRange(p.IntrinsicAbilities);
            }
            return(abils.Where(a => a.Rule == null || a.Rule.CanTarget(obj.AbilityTarget)));
        }
Ejemplo n.º 8
0
    protected override void DoDamage(RaycastHit2D hit)
    {
        IAbilityObject obj = explosionObject.Spawn(Ability, Multiplier);

        if (obj is ISetTargetPosition positionSetter)
        {
            positionSetter.SetTargetPosition(transform.position);
        }

        Destroy(gameObject);
    }
Ejemplo n.º 9
0
        /// <summary>
        /// Determines if an object has a specified ability.
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="abilityName"></param>
        /// <returns></returns>
        public static bool HasAbility(this IAbilityObject obj, string abilityName, bool includeShared = true)
        {
            IEnumerable <Ability> abils;

            if (includeShared && obj is IOwnableAbilityObject)
            {
                abils = obj.UnstackedAbilities(true).Union(obj.SharedAbilities());
            }
            else
            {
                abils = obj.UnstackedAbilities(true);
            }
            return(abils.Any(abil => abil.Rule != null && abil.Rule.Matches(abilityName)));
        }
Ejemplo n.º 10
0
        /// <summary>
        /// All abilities belonging to an object.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static IEnumerable <Ability> Abilities(this IAbilityObject obj, Func <IAbilityObject, bool> sourceFilter = null)
        {
            if (obj == null)
            {
                return(Enumerable.Empty <Ability>());
            }

            if (sourceFilter == null && Galaxy.Current != null && Galaxy.Current.IsAbilityCacheEnabled)
            {
                // use the ability cache
                if (Galaxy.Current.AbilityCache[obj] == null)
                {
                    Galaxy.Current.AbilityCache[obj] = obj.UnstackedAbilities(true, sourceFilter).Stack(obj).ToArray();
                }
                return(Galaxy.Current.AbilityCache[obj]);
            }

            return(obj.UnstackedAbilities(true, sourceFilter).Stack(obj));
        }
Ejemplo n.º 11
0
        public static IEnumerable <IAbilityObject> Ancestors(this IAbilityObject obj, Func <IAbilityObject, bool> sourceFilter = null)
        {
            if (obj == null)
            {
                yield break;
            }
            // TODO - filter out duplicate ancestors
            foreach (var p in obj.Parents.ExceptSingle(null))
            {
                if (p != null && (sourceFilter == null || sourceFilter(p)))
                {
                    yield return(p);

                    foreach (var x in p.Ancestors(sourceFilter))
                    {
                        yield return(x);
                    }
                }
            }
        }
Ejemplo n.º 12
0
        public static IEnumerable <IAbilityObject> Descendants(this IAbilityObject obj, Func <IAbilityObject, bool> sourceFilter = null)
        {
            var result = new HashSet <IAbilityObject>();

            if (obj != null)
            {
                foreach (var c in obj.Children)
                {
                    if (c != null && !result.Contains(c) && (sourceFilter == null || sourceFilter(c)))
                    {
                        result.Add(c);
                        foreach (var x in c.Descendants(sourceFilter))
                        {
                            result.Add(x);
                        }
                    }
                }
            }
            return(result);
        }
Ejemplo n.º 13
0
        public static IEnumerable <IAbilityObject> Descendants(this IAbilityObject obj, Func <IAbilityObject, bool>?sourceFilter = null)
        {
            // we can't use a HashSet here because e.g. ships can have multiples of the same engine template installed
            List <IAbilityObject> result = new();

            if (obj != null)
            {
                foreach (var c in obj.Children)
                {
                    if (c is not null && (sourceFilter is null || sourceFilter(c)))
                    {
                        result.Add(c);
                        foreach (var x in c.Descendants(sourceFilter))
                        {
                            result.Add(x);
                        }
                    }
                }
            }
            return(result);
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Gets any abilities that can be activated.
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static IDictionary <Ability, IAbilityObject> ActivatableAbilities(this IAbilityObject o)
        {
            if (o is Vehicle)
            {
                return(((Vehicle)o).ActivatableAbilities());
            }
            if (o is Planet)
            {
                return(((Planet)o).ActivatableAbilities());
            }

            var dict = new Dictionary <Ability, IAbilityObject>();

            foreach (var a in o.Abilities())
            {
                if (a.Rule.IsActivatable)
                {
                    dict.Add(a, o);
                }
            }
            return(dict);
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Finds empire-common abilities inherited by an object (e.g. empire abilities of a sector in which a ship resides).
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="sourceFilter"></param>
        /// <returns></returns>
        public static IEnumerable <Ability> EmpireCommonAbilities(this IAbilityObject obj, Func <IAbilityObject, bool> sourceFilter = null)
        {
            // Unowned objects cannot empire common abilities.
            var ownable = obj as IOwnableAbilityObject;

            if (ownable == null || ownable.Owner == null)
            {
                yield break;
            }

            // Where are these abilities coming from?
            // Right now they can only come from ancestors, since sectors and star systems are the only common ability objects.
            // TODO - Would it make sense for them to come from descendants? What kind of common ability object could be used as a descendant of an owned object?
            var ancestors = obj.Ancestors(sourceFilter).OfType <ICommonAbilityObject>();

            // What abilities do we have?
            foreach (var ancestor in ancestors)
            {
                foreach (var abil in ancestor.EmpireAbilities(ownable.Owner, sourceFilter))
                {
                    yield return(abil);
                }
            }
        }
Ejemplo n.º 16
0
 public static ILookup <Ability, Ability> AbilityTree(this IAbilityObject obj, Func <IAbilityObject, bool> sourceFilter = null)
 {
     return(obj.UnstackedAbilities(true, sourceFilter).StackToTree(obj));
 }
Ejemplo n.º 17
0
        public static string GetAbilityValue(this IEnumerable <IAbilityObject> objs, string name, IAbilityObject stackTo, int index = 1, bool includeShared = true, bool includeEmpireCommon = true, Func <Ability, bool> filter = null)
        {
            var tuples = objs.Squash(o => o.Abilities());

            if (includeShared)
            {
                tuples = tuples.Union(objs.Squash(o => o.SharedAbilities()));
            }
            if (includeEmpireCommon)
            {
                tuples = tuples.Union(objs.Squash(o => o.EmpireCommonAbilities()));
            }
            var abils = tuples.GroupBy(t => new { Rule = t.Item2.Rule, Object = t.Item1 }).Where(g => g.Key.Rule.Matches(name) && g.Key.Rule.CanTarget(g.Key.Object.AbilityTarget)).SelectMany(x => x).Select(t => t.Item2).Where(a => filter == null || filter(a)).Stack(stackTo);

            if (!abils.Any())
            {
                return(null);
            }
            return(abils.First().Values[index - 1]);
        }
Ejemplo n.º 18
0
 public static ILookup <Ability, Ability> StackAbilitiesToTree(this IEnumerable <IAbilityObject> objs, IAbilityObject stackTo)
 {
     return(objs.SelectMany(obj => obj.Abilities()).StackToTree(stackTo));
 }
Ejemplo n.º 19
0
        private ILookup <Ability, Ability> Stack(IEnumerable <Ability> abilities, IAbilityObject stackingTo, bool groupStacking)
        {
            if (abilities.Count() <= 1)
            {
                return(abilities.ToLookup(a => a, a => a));
            }

            var results = new SafeDictionary <Ability, Ability>();            // keys = original abilities, values = stacked abilities

            foreach (var abil in abilities)
            {
                for (int i = 0; i < abil.Values.Count; i++)
                {
                    AbilityValueRule rule;
                    if (groupStacking)
                    {
                        rule = GroupRules.ElementAtOrDefault(i);
                    }
                    else
                    {
                        rule = ValueRules.ElementAtOrDefault(i);
                    }
                    // TODO - don't repeatedly convert to/from strings, just do it once outside the loop
                    double?oldval = null;
                    if (results[abil] != null)
                    {
                        oldval = results[abil].Values.Count > i ? (double?)results[abil].Values[i].Value.ToDouble() : null;
                    }
                    else
                    {
                        var match = results.Values.Distinct().Where(a => a != null).SingleOrDefault(a => a.Rule == abil.Rule && a.Values.Select((val, idx) => rule != AbilityValueRule.Group && rule != AbilityValueRule.None || a.Values.Count >= abil.Values.Count && a.Values[idx] == abil.Values[idx]).All(b => b));

                        if (match != null)
                        {
                            results[abil] = match;
                            oldval        = results[abil].Values.Count > i ? (double?)results[abil].Values[i].Value.ToDouble() : null;
                        }
                        else
                        {
                            results[abil] = new Ability(stackingTo, abil.Rule);
                        }
                    }
                    double incoming = abil.Values.Count > i ? abil.Values[i].Value.ToDouble() : 0;
                    double newval   = oldval ?? 0;
                    if (rule == AbilityValueRule.Add)
                    {
                        newval = (oldval ?? 0) + incoming;
                    }
                    else if (rule == AbilityValueRule.TakeAverage)
                    {
                        newval = (oldval ?? 0) + incoming / abilities.Count();
                    }
                    else if (rule == AbilityValueRule.TakeHighest)
                    {
                        if (oldval == null)
                        {
                            newval = incoming;
                        }
                        else
                        {
                            newval = Math.Max(oldval.Value, incoming);
                        }
                    }
                    else if (rule == AbilityValueRule.TakeLowest)
                    {
                        if (oldval == null)
                        {
                            newval = incoming;
                        }
                        else
                        {
                            newval = Math.Min(oldval.Value, incoming);
                        }
                    }
                    else                     // group or none
                    {
                        newval = incoming;
                    }
                    if (results[abil].Values.Count > i)
                    {
                        results[abil].Values[i] = newval.ToString(CultureInfo.InvariantCulture);
                    }
                    else
                    {
                        while (results[abil].Values.Count < i)
                        {
                            results[abil].Values.Add(null);
                        }
                        results[abil].Values.Add(newval.ToString(CultureInfo.InvariantCulture));
                    }
                }
            }
            foreach (var kvp in results)
            {
                if (results.Values.Where(a => a == kvp.Value).Count() == 1)
                {
                    // ability is "stacked" alone, just use the original ability description
                    results[kvp.Key].Description = kvp.Key.Description;
                }
            }
            return(results.ToLookup(kvp => kvp.Value, kvp => kvp.Key));
        }
Ejemplo n.º 20
0
        /// <summary>
        /// Groups and stacks abilities.
        /// </summary>
        /// <param name="abilities"></param>
        /// <returns></returns>
        public ILookup <Ability, Ability> GroupAndStack(IEnumerable <Ability> abilities, IAbilityObject stackingTo)
        {
            var ours = abilities.Where(a => a.Rule == this).ToArray();

            // group abilities
            var dict         = new SafeDictionary <IList <string>, ICollection <Ability> >();
            var groupIndices = new List <int>();

            for (int i = 0; i < ValueRules.Count; i++)
            {
                if (ValueRules[i] == AbilityValueRule.Group)
                {
                    groupIndices.Add(i);
                }
            }
            foreach (var a in ours)
            {
                // treat non-group indices as "equal" for grouping purposes
                var key         = a.Values.Select((v, i) => groupIndices.Contains(i) ? v.Value : "").ToList();
                var existingKey = dict.Keys.SingleOrDefault(k => k.SequenceEqual(key));
                if (existingKey == null)
                {
                    dict[key] = new List <Ability>();
                    dict[key].Add(a);
                }
                else
                {
                    dict[existingKey].Add(a);
                }
            }

            // stack abilities
            var stackedInGroups = new SafeDictionary <Ability, IEnumerable <Ability> >();

            foreach (var group in dict.Values)
            {
                var stacked = Stack(group, stackingTo, false);
                foreach (var stack in stacked)
                {
                    stackedInGroups.Add(stack.Key, stack);
                }
            }

            var final = new List <Tuple <Ability, Ability> >();

            // stack grouped abilities if needed
            if (ValueRules.Any(r => r == AbilityValueRule.Group))
            {
                var groupLeaders = stackedInGroups.Select(g => g.Key);
                var stacked      = Stack(groupLeaders, stackingTo, true);
                foreach (var stack in stacked)
                {
                    foreach (var a in stack)
                    {
                        final.Add(Tuple.Create(stack.Key, a));
                    }
                }
            }
            else
            {
                foreach (var group in stackedInGroups)
                {
                    final.Add(Tuple.Create(group.Key, group.Key));
                }
            }

            return(final.ToLookup(t => t.Item1, t => t.Item2));
        }
Ejemplo n.º 21
0
 public static IEnumerable <Ability> Stack(this IEnumerable <Ability> abilities, IAbilityObject stackTo)
 {
     return(abilities.StackToTree(stackTo).Select(g => g.Key));
 }
Ejemplo n.º 22
0
 public static void ClearAbilityCache(this IAbilityObject o)
 {
     Galaxy.Current.AbilityCache.Remove(o);
 }
Ejemplo n.º 23
0
        /// <summary>
        /// Stacks any abilities of the same type according to the current mod's stacking rules.
        /// Keeps the original abilities in a handy tree format under the stacked abilities
        /// so you can tell which abilities contributed to which stacked abilities.
        /// </summary>
        /// <param name="abilities"></param>
        /// <param name="stackTo">The object which should own the stacked abilities.</param>
        /// <returns></returns>
        public static ILookup <Ability, Ability> StackToTree(this IEnumerable <Ability> abilities, IAbilityObject stackTo)
        {
            var stacked = new List <Tuple <Ability, Ability> >();
            var grouped = abilities.GroupBy(a => a.Rule);

            foreach (var group in grouped)
            {
                if (group.Key == null)
                {
                    continue;                     // invalid ability rule
                }
                var lookup = group.Key.GroupAndStack(group, stackTo);
                foreach (var lgroup in lookup)
                {
                    foreach (var abil in group)
                    {
                        stacked.Add(Tuple.Create(lgroup.Key, abil));
                    }
                }
            }
            return(stacked.ToLookup(t => t.Item1, t => t.Item2));
        }
Ejemplo n.º 24
0
        private void btnOK_Click(object sender, EventArgs e)
        {
            var selRows = gridAbilities.SelectedRows.Cast <DataGridViewRow>();

            if (selRows.Count() != 1)
            {
                // TODO - allow activation of multiple abilities at once
                MessageBox.Show("Please select a single ability to activate.");
            }
            else
            {
                dynamic      sel = selRows.Single().DataBoundItem;
                DialogResult result;
                // TODO - "Space Object Destroyed On Use" ability
                if (sel.IsDestroyedOnUse)
                {
                    IAbilityObject toBeDestroyed = sel.Source is IHull ? sobj : sel.Source;
                    result = MessageBox.Show("Activate this ability of " + sel.Source + "?\n" + sel.Ability + "\n" + toBeDestroyed + " will be destroyed!", "Confirm Activation", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                }
                else
                {
                    result = MessageBox.Show("Activate this ability of " + sel.Source + "?\n" + sel.Ability, "Confirm Activation", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                }
                if (result == DialogResult.Yes)
                {
                    bool needsTarget;
                    IEnumerable <IReferrable> targets = Enumerable.Empty <IReferrable>();
                    IReferrable target     = null;
                    string      targetType = "targets";
                    var         abil       = sel.Ability as Ability;
                    var         src        = sel.Source as IAbilityObject;

                    Func <string> customCheck = () => null;                    // custom check for space objects being able to do stuff
                    // TODO - move custom check functions into a utility class for use on the server side too
                    if (abil.Rule.Matches("Emergency Resupply"))
                    {
                        // TODO - allow resupplying other ships nearby?
                        needsTarget = false;
                    }
                    else if (abil.Rule.Matches("Emergency Energy"))
                    {
                        needsTarget = false;
                    }
                    else if (abil.Rule.Matches("Self-Destruct"))
                    {
                        needsTarget = false;
                    }
                    else if (abil.Rule.Matches("Open Warp Point"))
                    {
                        // find systems in range
                        needsTarget = true;
                        targets     = Galaxy.Current.StarSystemLocations.Where(l => sobj.StarSystem != l.Item && sobj.StarSystem.Coordinates.EightWayDistance(l.Location) <= abil.Value1.ToInt()).Select(l => l.Item);
                        targetType  = "star systems within {0} light-years".F(abil.Value1);
                    }
                    else if (abil.Rule.Matches("Close Warp Point"))
                    {
                        // find warp points in sector
                        needsTarget = true;
                        targets     = sobj.Sector.SpaceObjects.OfType <WarpPoint>();
                        targetType  = "warp points";
                    }
                    else if (abil.Rule.Matches("Create Planet"))
                    {
                        // find asteroids in sector, and make sure there's at least one star
                        needsTarget = true;
                        targets     = sobj.Sector.SpaceObjects.OfType <AsteroidField>();
                        targetType  = "asteroid fields";
                        customCheck = () =>
                        {
                            if (!sobj.StarSystem.FindSpaceObjects <Star>().Any())
                            {
                                return("We can't create a planet in a system without a star.");
                            }
                            return(null);
                        };
                    }
                    else if (abil.Rule.Matches("Destroy Planet"))
                    {
                        // find planets in sector that are small enough to destroy
                        needsTarget = true;
                        targets     = sobj.Sector.SpaceObjects.OfType <Planet>().Where(p => (int)p.StellarSize <= abil.Value1.ToInt());
                        targetType  = "planets not exceeding size {0}".F(abil.Value1);
                    }
                    else if (abil.Rule.Matches("Create Star"))
                    {
                        // make sure this isn't a special star system but it doesn't have any stars in it
                        needsTarget = false;
                        customCheck = () =>
                        {
                            // TODO - implement star system physical type

                            /*
                             * if (sobj.StarSystem.PhysicalType != StarSystemPhysicalType.Empty)
                             *      return "We can only create a star in an empty system.";
                             */
                            return(null);
                        };
                    }
                    else if (abil.Rule.Matches("Destroy Star"))
                    {
                        // find stars in sector
                        needsTarget = true;
                        targets     = sobj.Sector.SpaceObjects.OfType <Star>();
                        targetType  = "stars";
                    }
                    else if (abil.Rule.Matches("Create Storm"))
                    {
                        needsTarget = false;
                    }
                    else if (abil.Rule.Matches("Destroy Storm"))
                    {
                        // find storms in sector
                        needsTarget = true;
                        targets     = sobj.Sector.SpaceObjects.OfType <Storm>();
                        targetType  = "storms";
                    }
                    else if (abil.Rule.Matches("Create Nebula"))
                    {
                        // don't need to pick a star, just make sure one exists
                        needsTarget = false;
                        customCheck = () =>
                        {
                            if (!sobj.Sector.SpaceObjects.OfType <Star>().Any())
                            {
                                return("Creating a nebula requires a star in the sector.");
                            }
                            return(null);
                        };
                    }
                    else if (abil.Rule.Matches("Destroy Nebula"))
                    {
                        needsTarget = false;
                        customCheck = () =>
                        {
                            // TODO - implement star system physical type

                            /*
                             * if (sobj.StarSystem.PhysicalType != StarSystemPhysicalType.Nebulae)
                             *      return "There is no nebula in this system to destroy.";
                             */
                            return(null);
                        };
                    }
                    else if (abil.Rule.Matches("Create Black Hole"))
                    {
                        // don't need to pick a star, just make sure one exists
                        needsTarget = false;
                        customCheck = () =>
                        {
                            if (!sobj.Sector.SpaceObjects.OfType <Star>().Any())
                            {
                                return("Creating a black hole requires a star in the sector.");
                            }
                            return(null);
                        };
                    }
                    else if (abil.Rule.Matches("Destroy Black Hole"))
                    {
                        needsTarget = false;
                        customCheck = () =>
                        {
                            // TODO - implement star system physical type

                            /*
                             * if (sobj.StarSystem.PhysicalType != StarSystemPhysicalType.BlackHole)
                             *      return "There is no black hole in this system to destroy.";
                             */
                            return(null);
                        };
                    }
                    else if (abil.Rule.Matches("Create Constructed Planet From Star"))
                    {
                        // find stars in sector
                        needsTarget = true;
                        targets     = sobj.Sector.SpaceObjects.OfType <Star>();
                        targetType  = "stars";
                    }
                    else if (abil.Rule.Matches("Create Constructed Planet From Planet"))
                    {
                        // find planets in sector
                        needsTarget = true;
                        targets     = sobj.Sector.SpaceObjects.OfType <Planet>();
                        targetType  = "planets";
                    }
                    else if (abil.Rule.Matches("Create Constructed Planet From Storm"))
                    {
                        // find storms in sector
                        needsTarget = true;
                        targets     = sobj.Sector.SpaceObjects.OfType <Storm>();
                        targetType  = "storms";
                    }
                    else if (abil.Rule.Matches("Create Constructed Planet From Warp Point"))
                    {
                        // find warp points in sector
                        needsTarget = true;
                        targets     = sobj.Sector.SpaceObjects.OfType <WarpPoint>();
                        targetType  = "warp points";
                    }
                    else if (abil.Rule.Matches("Create Constructed Planet From Asteroids"))
                    {
                        // find asteroids in sector
                        needsTarget = true;
                        targets     = sobj.Sector.SpaceObjects.OfType <AsteroidField>();
                    }
                    else if (abil.Rule.Matches("Create Constructed Planet From Space"))
                    {
                        needsTarget = false;
                    }
                    else
                    {
                        MessageBox.Show(abil + " cannot be activated.");
                        return;
                    }

                    // check for targets
                    if (needsTarget)
                    {
                        if (!targets.Any())
                        {
                            MessageBox.Show("There are no suitable {0} available.".F(targetType));
                            return;
                        }
                    }

                    // check custom conditions
                    var error = customCheck();
                    if (error != null)
                    {
                        MessageBox.Show(error);
                        return;
                    }

                    // pick target
                    if (needsTarget)
                    {
                        var picker = new GenericPickerForm(targets);
                        this.ShowChildForm(picker);
                        if (picker.DialogResult == DialogResult.OK)
                        {
                            target = picker.SelectedObject as IReferrable;
                        }
                        else
                        {
                            return;
                        }
                    }

                    // issue command
                    var order = new ActivateAbilityOrder(sel.Source, sel.Ability, target);
                    var cmd   = new AddOrderCommand(sobj, order);
                    cmd.Execute();
                    Empire.Current.Commands.Add(cmd);
                    Close();
                }
            }
        }