Exemple #1
0
        /// <summary>
        /// Adds to a fleet without refreshing the GUI.
        /// </summary>
        /// <param name="vehicle"></param>
        /// <param name="fleet"></param>
        private void DoAddToFleet(IMobileSpaceObject vehicle, Fleet fleet)
        {
            if (vehicle == null)
            {
                return;
            }
            if (fleet == null)
            {
                return;
            }

            JoinFleetCommand cmd;

            if (!newFleets.Contains(fleet))
            {
                // fleet already exists, we can add to it
                cmd = new JoinFleetCommand(vehicle, fleet);
            }
            else
            {
                // fleet is new, we need to reference it by its command
                cmd = new JoinFleetCommand(vehicle, newCommands.OfType <CreateFleetCommand>().Single(c => c.Fleet == fleet));
            }
            newCommands.Add(cmd);
        }
Exemple #2
0
        public IEnumerable <LogMessage> GetErrors(IMobileSpaceObject executor, IRecyclable target)
        {
            if (target == null)
            {
                yield return(new GenericLogMessage("A scrap order was issued for a nonexistent target."));

                yield break;
            }
            if (target.IsDisposed)
            {
                yield return(target.CreateLogMessage($"{target} cannot be scrapped because it is already destroyed."));
            }
            if (target.RecycleContainer != executor)
            {
                yield return(target.CreateLogMessage(target + " cannot be scrapped by " + executor + " because " + target + " does not belong to " + executor + "."));
            }
            if ((target is Ship || target is Base) && !executor.Sector.SpaceObjects.Any(sobj => sobj.Owner == executor.Owner && sobj.HasAbility("Space Yard")))
            {
                yield return(target.CreateLogMessage(target + " cannot be scrapped at " + executor.Sector + " because there is no space yard present in that sector."));
            }
            if ((target is IUnit) && !executor.Sector.SpaceObjects.Any(sobj => sobj.Owner == executor.Owner && (sobj is Planet || sobj.HasAbility("Space Yard"))))
            {
                yield return(target.CreateLogMessage(target + " cannot be scrapped at " + executor.Sector + " because there is no space yard or colony present in that sector."));
            }
        }
Exemple #3
0
        /// <summary>
        /// Adds a vehicle or fleet to a fleet.
        /// </summary>
        /// <param name="vehicle"></param>
        /// <param name="fleet"></param>
        private void AddToFleet(IMobileSpaceObject vehicle, Fleet fleet)
        {
            DoAddToFleet(vehicle, fleet);

            BindVehicles();
            BindFleets(fleet);
            changed = true;
        }
Exemple #4
0
        /// <summary>
        /// Recursively builds a tree node for a fleet or vehicle.
        /// </summary>
        /// <param name="tree">Should be a TreeView or TreeNode.</param>
        /// <param name="sobj">The fleet or vehicle.</param>
        private void BuildVehicleTreeNode(object tree, IMobileSpaceObject sobj)
        {
            TreeNode node;

            string CalculateSupplyStatus(int remaining, int storage)
            {
                if (remaining == 0)
                {
                    return("Supplies Empty");
                }
                if (remaining < storage * 0.5)
                {
                    return("Low Supplies");
                }
                return("");
            }

            string CalculateStatus(IMobileSpaceObject sobj2)
            {
                var s   = "Speed " + sobj2.StrategicSpeed;
                var sup = CalculateSupplyStatus(sobj2.SupplyRemaining, sobj2.SupplyStorage);

                if (sup == null)
                {
                    return(s);
                }
                else
                {
                    return($"{s}, {sup}");
                }
            }

            var namestr = $"{sobj.Name}: {CalculateStatus(sobj)}";

            if (tree is TreeView)
            {
                node = ((TreeView)tree).AddItemWithImage(namestr, sobj, sobj.Icon);
            }
            else if (tree is TreeNode)
            {
                node = ((TreeView)tree).AddItemWithImage(namestr, sobj, sobj.Icon);
            }
            else
            {
                throw new ArgumentException("Tree for BuildVehicleTreeNode must be a TreeView or TreeNode.", "tree");
            }
            if (sobj is Fleet)
            {
                foreach (var sobj2 in ((Fleet)sobj).Vehicles)
                {
                    BuildVehicleTreeNode(node, sobj2);
                }
            }
        }
Exemple #5
0
        /// <summary>
        /// Navigation for space objects.
        /// </summary>
        /// <param name="me"></param>
        /// <param name="start"></param>
        /// <param name="end"></param>
        /// <param name="avoidEnemies"></param>
        /// <returns></returns>
        public static IEnumerable <Sector> Pathfind(IMobileSpaceObject me, Sector start, Sector end, bool avoidEnemies, bool avoidDamagingSectors, IDictionary <PathfinderNode <Sector>, ISet <PathfinderNode <Sector> > > map)
        {
            bool cacheEnabled = Galaxy.Current.IsAbilityCacheEnabled;

            if (!cacheEnabled)
            {
                Galaxy.Current.EnableAbilityCache();
            }
            if (end == null || end.StarSystem == null || start == end)
            {
                return(Enumerable.Empty <Sector>());
            }
            if (me != null && me.StrategicSpeed < 1)
            {
                return(Enumerable.Empty <Sector>());
            }

            if (map == null)
            {
                map = CreateDijkstraMap(me, start, end, avoidEnemies, avoidDamagingSectors);
            }

            if (!map.Any())
            {
                return(Enumerable.Empty <Sector>());               // nowhere to go!
            }
            var nodes = new List <PathfinderNode <Sector> >();
            PathfinderNode <Sector> node;

            if (map.Keys.Any(n => n.Location == end))
            {
                // can reach it
                node = map.Keys.Where(n => n.Location == end).OrderBy(n => n.Cost).First();
            }
            else
            {
                // can't reach it; get as close as possible
                var dist = map.Keys.Min(n => n.MinimumCostRemaining);
                node = map.Keys.First(n => n.MinimumCostRemaining == dist);
            }

            while (node != null)
            {
                nodes.Add(node);
                node = node.PreviousNode;
            }
            if (!cacheEnabled)
            {
                Galaxy.Current.DisableAbilityCache();
            }
            return(nodes.Select(n => n.Location).Where(s => s != start).Reverse());
        }
Exemple #6
0
        private TreeNode CreateNode(TreeView parent, IMobileSpaceObject v)
        {
            var node = parent.AddItemWithImage(v.Name, v, v.Icon);

            if (v is Fleet)
            {
                foreach (var sub in ((Fleet)v).Vehicles)
                {
                    CreateNode(node, sub);
                }
            }
            return(node);
        }
Exemple #7
0
        private TreeNode CreateNode(TreeNode parent, IMobileSpaceObject v)
        {
            TreeNode node;

            node = parent.AddItemWithImage(v.Name + ": " + CalculateStatus(v), v, v.Icon);
            if (v is Fleet)
            {
                foreach (var sub in ((Fleet)v).Vehicles)
                {
                    CreateNode(node, sub);
                }
            }
            return(node);
        }
Exemple #8
0
        private string CalculateStatus(IMobileSpaceObject sobj2)
        {
            var s   = "Speed " + sobj2.StrategicSpeed;
            var sup = CalculateSupplyStatus(sobj2.SupplyRemaining, sobj2.SupplyStorage);

            if (sup == null)
            {
                return(s);
            }
            else
            {
                return($"{s}, {sup}");
            }
        }
Exemple #9
0
        /// <summary>
        /// Finds the path for executing this order.
        /// </summary>
        /// <param name="sobj">The space object executing the order.</param>
        /// <returns></returns>
        public override IEnumerable <Sector> Pathfind(IMobileSpaceObject me, Sector start)
        {
            if (Target is IMobileSpaceObject)
            {
                if (me.CanWarp && !Target.CanWarp)
                {
                    // warping via any warp point that leads outside the system should be safe, so prioritize those!
                    var sys   = me.FindStarSystem();
                    var paths = sys.FindSpaceObjects <WarpPoint>()
                                .Where(wp => wp.TargetStarSystemLocation == null || wp.TargetStarSystemLocation.Item != sys)
                                .Select(wp => new { WarpPoint = wp, Path = Pathfinder.Pathfind(me, start, wp.Sector, AvoidEnemies, true, me.DijkstraMap) });
                    if (paths.Any())
                    {
                        // found a warp point to flee to!
                        var shortest = paths.WithMin(path => path.Path.Count()).PickRandom();
                        return(shortest.Path.Concat(new Sector[] { shortest.WarpPoint.Target }));
                    }
                }

                // see how he can reach us, and go somewhere away from him (that would take longer for him to get to than
                var dijkstraMap = Pathfinder.CreateDijkstraMap((IMobileSpaceObject)Target, Target.Sector, me.FindSector(), false, true);
                var canMoveTo   = Pathfinder.GetPossibleMoves(me.Sector, me.CanWarp, me.Owner);
                var goodMoves   = canMoveTo.Where(s => !dijkstraMap.Values.SelectMany(set => set).Any(n => n.Location == s));

                if (goodMoves.Any())
                {
                    // just go there and recompute the path next time we can move - the enemy may have moved too
                    return(new Sector[] { goodMoves.PickRandom() });
                }
                else
                {
                    // trapped...
                    return(Enumerable.Empty <Sector>());
                }
            }
            else
            {
                // target is immobile! no need to flee, unless it's in the same sector
                if (Target.Sector == me.FindSector())
                {
                    // don't need to go through warp points to evade it, the warp points might be one way!
                    var moves = Pathfinder.GetPossibleMoves(me.Sector, false, me.Owner);
                    return(new Sector[] { moves.PickRandom() });
                }
                else
                {
                    return(Enumerable.Empty <Sector>());
                }
            }
        }
Exemple #10
0
        public ActivateAbilityForm(IMobileSpaceObject sobj)
        {
            InitializeComponent();

            this.sobj = sobj;

            var abils = sobj.ActivatableAbilities().Select(kvp => new
            {
                Ability          = kvp.Key,
                Source           = kvp.Value,
                IsDestroyedOnUse = kvp.Value.HasAbility("Destroyed On Use"),
                // TODO - "Space Object Destroyed On Use" ability
            });

            gridAbilities.DataSource = abils;
        }
Exemple #11
0
        private TreeNode FindNode(TreeNode parent, IMobileSpaceObject v)
        {
            foreach (TreeNode n in parent.Nodes)
            {
                if (n.Tag == v)
                {
                    return(n);
                }
                var sub = FindNode(n, v);
                if (sub != null)
                {
                    return(sub);
                }
            }

            return(null);
        }
Exemple #12
0
        /// <summary>
        /// Removes a vehicle or fleet from its fleet.
        /// </summary>
        /// <param name="sobj"></param>
        private void RemoveFromFleet(IMobileSpaceObject vehicle)
        {
            if (vehicle == null)
            {
                return;
            }
            if (vehicle.Container == null)
            {
                return;
            }

            var cmd = new LeaveFleetCommand(vehicle);

            newCommands.Add(cmd);
            BindVehicles(vehicle);
            var node = treeFleets.GetAllNodes().Single(x => x.Tag == vehicle);

            node.Remove();
            changed = true;
        }
Exemple #13
0
 protected abstract bool AreWeThereYet(IMobileSpaceObject me);
Exemple #14
0
 /// <summary>
 /// Finds the path for executing this order.
 /// </summary>
 /// <param name="sobj">The space object executing the order.</param>
 /// <param name="start">The start location (need not be the current location, in case there are prior orders queued).</param>
 /// <returns></returns>
 public abstract IEnumerable<Sector> Pathfind(IMobileSpaceObject me, Sector start);
Exemple #15
0
 public IDictionary<PathfinderNode<Sector>, ISet<PathfinderNode<Sector>>> CreateDijkstraMap(IMobileSpaceObject me, Sector start)
 {
     return Pathfinder.CreateDijkstraMap(me, start, Destination, AvoidEnemies, true);
 }
Exemple #16
0
 /// <summary>
 /// Finds the path for executing this order.
 /// </summary>
 /// <param name="sobj">The space object executing the order.</param>
 /// <returns></returns>
 public IEnumerable <Sector> Pathfind(IMobileSpaceObject me, Sector start)
 {
     return(Pathfinder.Pathfind(me, start, Destination, AvoidEnemies, true, me.DijkstraMap));
 }
Exemple #17
0
 protected override bool AreWeThereYet(IMobileSpaceObject me)
 {
     // gotta keep on running...
     return(Target == null || Target.IsDisposed);
 }
Exemple #18
0
        public static IDictionary <PathfinderNode <Sector>, ISet <PathfinderNode <Sector> > > CreateDijkstraMap(IMobileSpaceObject me, Sector start, Sector end, bool avoidEnemies, bool avoidDamagingSectors)
        {
            // step 2a (do it here so we can return map if start or end is null): empty map with nodes, their costs, and previous-node references
            var map = new Dictionary <PathfinderNode <Sector>, ISet <PathfinderNode <Sector> > >();

            // if we are nowhere or we're going nowhere, that's impossible!
            if (start == null || end == null)
            {
                return(map);
            }

            var startSys = start.StarSystem;

            // pathfind!
            // step 1: empty priority queue with cost to reach each node
            var queue = new Dictionary <int, ISet <PathfinderNode <Sector> > >();

            // step 2b: empty set of previously visited nodes
            var visited = new HashSet <Sector>();

            // step 3: add start node and cost
            queue.Add(0, new HashSet <PathfinderNode <Sector> >());
            queue[0].Add(new PathfinderNode <Sector>(start, 0, null, EstimateDistance(start, end, me == null ? null : me.Owner)));

            // step 4: quit if there are no nodes (all paths exhausted without finding goal)
            bool success = false;

            while (queue.SelectMany(kvp => kvp.Value).Any() && !success)
            {
                // step 5: take lowest cost node out of queue
                // TODO - also prefer straight line movement to diagonal?
                var minCost = queue.Keys.Min();
                while (!queue[minCost].Any())
                {
                    queue.Remove(minCost);
                    minCost = queue.Keys.Min();
                }
                var node = queue[minCost].First();
                queue[minCost].Remove(node);
                map.Add(node, new HashSet <PathfinderNode <Sector> >());

                // step 6: if node is the goal, stop after it's done - success!
                if (node.Location == end)
                {
                    success = true;
                }

                // step 7: check possible moves
                var moves = GetPossibleMoves(node.Location, me == null ? true : me.CanWarp, me == null ? null : me.Owner);

                // step 7a: remove blocked points (aka calculate cost)
                if (avoidEnemies)
                {
                    // avoid enemies, except at the destination
                    moves = moves.Where(m => m == null || m == end || !m.SpaceObjects.Where(sobj => sobj.CheckVisibility(me.Owner) >= Visibility.Visible || sobj.FindMemory(me.Owner)?.Sector == m).OfType <ICombatant>().Any(sobj => sobj.IsHostileTo(me == null ? null : me.Owner)));
                }
                if (avoidDamagingSectors)
                {
                    // don't avoid the destination, even if it is a damaging sector
                    moves = moves.Where(m => m == end || m == null || !m.SpaceObjects.Where(sobj => sobj.CheckVisibility(me.Owner) >= Visibility.Visible || sobj.FindMemory(me.Owner)?.Sector == m).Any(sobj => sobj.GetAbilityValue("Sector - Damage").ToInt() > 0));
                }

                // step 7b: update priority queue
                Action <Sector> f = move =>
                {
                    // When we lock the queue, we do so because it is being checked and modified by other threads,
                    // and we don't want them stepping on each other's toes.
                    // e.g. thread 1 is checking for the existence of an item in the queue
                    // while thread 2 is busy adding that same item!
                    if (!visited.Contains(move))
                    {
                        // didn't visit yet
                        var newnode = new PathfinderNode <Sector>(move, node.Cost + 1, node, EstimateDistance(move, end, me == null ? null : me.Owner));
                        lock (queue)
                        {
                            if (!queue.ContainsKey(newnode.Cost))
                            {
                                queue.Add(newnode.Cost, new HashSet <PathfinderNode <Sector> >());
                            }
                            queue[newnode.Cost].Add(newnode);
                        }
                        if (!map.ContainsKey(node))                         // don't need to lock map, we're only adding a node which should only get added once per run
                        {
                            map.Add(node, new HashSet <PathfinderNode <Sector> >());
                        }
                        map[node].Add(newnode);
                        visited.Add(move);
                    }
                    else
                    {
                        // already visited - but is it by a longer path?
                        var moreCost = queue.Where(kvp => kvp.Key > node.Cost + 1).SelectMany(kvp => kvp.Value);
                        var items    = moreCost.Where(n => n.Location == move && n.Cost > node.Cost + 1);
                        if (items.Any())
                        {
                            PathfinderNode <Sector> newnode;

                            foreach (var old in items.ToArray())
                            {
                                lock (queue[old.Cost]) queue[old.Cost].Remove(old);
                                map.Remove(old);
                            }
                            newnode = new PathfinderNode <Sector>(move, node.Cost + 1, node);
                            lock (queue[newnode.Cost]) queue[newnode.Cost].Add(newnode);
                            if (!map.ContainsKey(node))                              // don't need to lock map, we're only adding a node which should only get added once per run
                            {
                                map.Add(node, new HashSet <PathfinderNode <Sector> >());
                            }
                            map[node].Add(newnode);
                        }
                    }
                };
                moves.SafeForeach(f);
            }

            return(map);
        }
Exemple #19
0
 protected override bool AreWeThereYet(IMobileSpaceObject me)
 {
     return(me.Sector == Destination);
 }
Exemple #20
0
        private void BindVehicles(IMobileSpaceObject selected = null)
        {
            var vehicles = new HashSet <IVehicle>();

            // find vehicles in sector that are not fleets
            foreach (var v in sector.SpaceObjects.OfType <SpaceVehicle>().OwnedBy(Empire.Current))
            {
                vehicles.Add(v);
            }

            // add vehicles that are being removed from fleets (but not fleets themselves, those go in the fleets tree)
            foreach (var v in newCommands.OfType <LeaveFleetCommand>().Select(c => c.Executor).OfType <SpaceVehicle>())
            {
                vehicles.Add(v);
            }
            foreach (var v in newCommands.OfType <DisbandFleetCommand>().SelectMany(c => c.Executor.Vehicles.OfType <SpaceVehicle>()))
            {
                vehicles.Add(v);
            }

            // remove vehicles that are being added to fleets
            foreach (var v in newCommands.OfType <JoinFleetCommand>().Select(c => c.Executor).OfType <SpaceVehicle>())
            {
                vehicles.Remove(v);
            }

            // make a tree of vehicles
            treeVehicles.Initialize(32);
            foreach (var vtGroup in vehicles.GroupBy(v => v.Design.VehicleType))
            {
                var vtNode = treeVehicles.AddItemWithImage(vtGroup.Key.ToSpacedString(), vtGroup.Key, Pictures.GetVehicleTypeImage(Empire.Current.ShipsetPath, vtGroup.Key));
                foreach (var roleGroup in vtGroup.GroupBy(v => v.Design.Role))
                {
                    var roleNode = vtNode.AddItemWithImage(roleGroup.Key, roleGroup.Key, Pictures.GetVehicleTypeImage(Empire.Current.ShipsetPath, vtGroup.Key));
                    foreach (var designGroup in roleGroup.GroupBy(v => v.Design))
                    {
                        var designNode = roleNode.AddItemWithImage(designGroup.Key.Name, designGroup.Key, designGroup.Key.Icon);
                        foreach (var vehicle in designGroup)
                        {
                            TreeNode vehicleNode;
                            if (vehicle is IMobileSpaceObject sobj)                             // yay pattern matching! :D
                            {
                                vehicleNode = designNode.AddItemWithImage(vehicle.Name + ": " + CalculateStatus(sobj), vehicle, vehicle.Icon);
                            }
                            else
                            {
                                vehicleNode = designNode.AddItemWithImage(vehicle.Name, vehicle, vehicle.Icon);
                            }
                            if (vehicle == selected)
                            {
                                treeVehicles.SelectedNode = vehicleNode;
                            }
                        }
                    }
                }
                if (vtNode.Nodes.Count == 0)
                {
                    vtNode.Remove();
                }
            }

            // expand the treeeee!
            treeVehicles.ExpandAll();
        }