private void btnStandaloneAmmoFull_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                ShipPartDNA dna = GetDefaultDNA(AmmoBox.PARTTYPE);
                ModifyDNA(dna, chkStandaloneRandSize.IsChecked.Value, chkStandaloneRandOrientation.IsChecked.Value);

                AmmoBox ammoBox = new AmmoBox(_editorOptions, _itemOptions, dna);
                ammoBox.RemovalMultiple = ammoBox.QuantityMax * .1d;
                ammoBox.QuantityCurrent = ammoBox.QuantityMax;

                BuildStandalonePart(ammoBox);

                if (chkStandaloneShowMassBreakdown.IsChecked.Value)
                {
                    double cellSize = Math1D.Max(dna.Scale.X, dna.Scale.Y, dna.Scale.Z) * UtilityCore.GetScaledValue_Capped(.1d, .3d, 0d, 1d, _rand.NextDouble());
                    DrawMassBreakdown(ammoBox.GetMassBreakdown(cellSize), cellSize);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        private void btnEnergyToAmmo_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                ShipPartDNA dna = GetDefaultDNA(EnergyTank.PARTTYPE);
                EnergyTank energyTank = new EnergyTank(_editorOptions, _itemOptions, dna);

                dna = GetDefaultDNA(AmmoBox.PARTTYPE);
                AmmoBox ammoBox = new AmmoBox(_editorOptions, _itemOptions, dna);

                dna = GetDefaultDNA(ConverterEnergyToAmmo.PARTTYPE);
                ConverterEnergyToAmmo converter = new ConverterEnergyToAmmo(_editorOptions, _itemOptions, dna, energyTank, ammoBox);

                energyTank.QuantityCurrent = energyTank.QuantityMax;

                double mass = converter.DryMass;
                mass = converter.TotalMass;

                converter.Transfer(1d, .5d);
                converter.Transfer(1d, 1d);
                converter.Transfer(1d, .1d);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
 public GunAmmoGroup(GunGroup guns, AmmoBox[] ammo, int firings)
 {
     this.Guns = guns;
     this.Ammo = ammo;
     this.Firings = firings;
 }
        private void btnAmmoBox_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                ShipPartDNA dna = GetDefaultDNA(AmmoBox.PARTTYPE);
                AmmoBox ammoBox = new AmmoBox(_editorOptions, _itemOptions, dna);
                ammoBox.RemovalMultiple = ammoBox.QuantityMax * .1d;

                double mass1 = ammoBox.TotalMass;

                double remainder = ammoBox.AddQuantity(.05d, false);
                double mass2 = ammoBox.TotalMass;

                remainder = ammoBox.AddQuantity(500d, false);
                double mass3 = ammoBox.TotalMass;

                double output = ammoBox.RemoveQuantity(.1d, false);
                double mass4 = ammoBox.TotalMass;

                output = ammoBox.RemoveQuantity(ammoBox.RemovalMultiple * 2d, false);
                double mass5 = ammoBox.TotalMass;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        private static GunAmmoGroup[] GetAmmoGroupings_Assign(IEnumerable<GunGroup> guns, AmmoBox[] boxesDescending, Tuple<long, long, double>[] ammo_gun_distance)
        {
            // Build a structure that can be added to
            var retVal = guns.
                Select(o => new { Gun = o, Boxes = new List<AmmoBox>() }).
                ToArray();

            for (int cntr = 0; cntr < boxesDescending.Length; cntr++)
            {
                double boxVolume = boxesDescending[cntr].QuantityMax;
                double boxMinDimension = Math1D.Min(boxesDescending[cntr].ScaleActual.X, boxesDescending[cntr].ScaleActual.Y, boxesDescending[cntr].ScaleActual.Z);
                long boxToken = boxesDescending[cntr].Token;

                // Find the gun that most needs this box
                var bestMatch = retVal.
                    Where(o => o.Gun.DemandPerGun <= boxVolume && o.Gun.Caliber <= boxMinDimension).       // only look at guns that could use this box
                    Select(o =>
                    {
                        var capacityFirings = Get_Capacity_Firings(o.Boxes, o.Gun);

                        // Add up the distance between the box and all the guns in this group
                        double distance = o.Gun.Guns.Sum(p => ammo_gun_distance.First(q => q.Item1 == boxToken && q.Item2 == p.Token).Item3);

                        return new
                        {
                            Item = o,
                            Capacity = capacityFirings.Item1,       // the current amount of capacity this gun has
                            Firings = capacityFirings.Item2,     // how many shots can be fired based on this capacity
                            Distance = distance,
                        };
                    }).
                    //TODO: Figure out how to come up with a scoring system that takes distance into account
                    OrderBy(o => o.Firings).       // order by guns with the smallest amount of available shots
                    ThenByDescending(o => o.Item.Gun.DemandTotal).       // if there's a tie, choose the greediest gun
                    First();

                // Give this box to the chosen set of guns
                bestMatch.Item.Boxes.Add(boxesDescending[cntr]);
            }

            return retVal.
                Select(o => new GunAmmoGroup(o.Gun, o.Boxes.ToArray(), Convert.ToInt32(Math.Floor(Get_Capacity_Firings(o.Boxes, o.Gun).Item2)))).
                ToArray();
        }