UnitCost GetOverInfusionCosts(IUnitData unitData, int infusion, int excessKills)
        {
            // over infuse logic. Because this is annoyingly complex, it gets comments

            // We use recursion to get the cost of the previous infuse, then add on our current infusion
            var previousInfCost = GetInfusionCosts(unitData, infusion - 1, excessKills);
            var material        = new UnitRecepePiece(unitData.BasicType, 10, UnitRankType.None, 1);

            // Get the material count - this may not be correct, I only tested inf10->11, which was 11 units
            var materialQty = infusion;


            // check see if any qs charges will be involved in the cost of the infuse materials
            UnitCost qsMaterialCost     = default;
            var      remainingQsCharges = qsCharges;

            if (remainingQsCharges > 0)
            {
                // cost of the infuse feed if we have a qs charge
                qsMaterialCost = GetRawUnitCost(material);

                // as we need 10+ mats, we are going to exhaust our QS charges
                // at this stage it isn't possible to have more than 10 QS charges
                qsCharges = 0;
            }

            // get the cost of our unit without any qs charges
            var fullMaterialCost = GetRawUnitCost(material);

            // cost of feed, e.g, 3000 for inf 11, 4000 for inf 12;
            var mainUnitFeedCost = 2000 + (infusion - 10) * 1000;

            // at this stage it seems unrealistic we will get more than 11,000 vet, so it's unlikely there will be any kills on our materials.
            var killRecycleRefund = 0;

            // as we use recursion for each infuse, we should only get the bonus of one here
            var infuseRecycleRefund = GetInfuseRecycleRefund(1);

            // finally we can total it all together
            var materialKills    = fullMaterialCost.Kills * (materialQty - remainingQsCharges) + qsMaterialCost.Kills * remainingQsCharges;
            var materialMinerals = fullMaterialCost.Minerals * (materialQty - remainingQsCharges) + qsMaterialCost.Minerals * remainingQsCharges;
            var totalKillCost    = materialKills + mainUnitFeedCost - infuseRecycleRefund - killRecycleRefund;

            return(new UnitCost(previousInfCost.Minerals + materialMinerals, previousInfCost.Kills + totalKillCost, 0));
        }
        UnitCost GetInfusionCosts(IUnitData unitData, int infusion, int excessKills)
        {
#if DEBUG
            RecordDNAStartUnit(unitData, infusion);
#endif
            if (infusion < 11)
            {
                if (infusion == 0)
                {
                    return(new UnitCost(0, 0, excessKills));
                }

                var infuseDiscount = 0;
                if (unitData.Type.IsCoreBasic() && infusion >= 3 && TryUseQSCharge())
                {
                    infuseDiscount = 3;
                }

                if (unitData.Type.IsDNA1() && infusion >= loadout.Perks.DNAStart.DesiredLevel && TryUseDNAStart())
                {
                    infuseDiscount = loadout.Perks.DNAStart.DesiredLevel;
                }
                else if (shouldGrantDNAFreeInf1 && unitData.Type.IsDNA1())
                {
                    infuseDiscount = 1;
                }

                var material     = new UnitRecepePiece(unitData.BasicType, (int)unitData.Evolution, UnitRankType.None, 1);
                var materialCost = GetRawUnitCost(material);
                var(Cost, ExcessKills) = GetFeedCost(infusion, unitData.Type, excessKills, infuseDiscount);
                var materialQty         = UnitsRequiredForInfuse(infusion, infuseDiscount);
                var killRecycleRefund   = GetKillRecycleRefund(materialCost, infusion, infuseDiscount, materialQty);
                var infuseRecycleRefund = GetInfuseRecycleRefund(infusion, infuseDiscount);
                var totalKillCost       = materialCost.Kills * materialQty + Cost - infuseRecycleRefund - killRecycleRefund;
                return(new UnitCost(materialCost.Minerals * materialQty, totalKillCost, ExcessKills));
            }
            else
            {
                return(GetOverInfusionCosts(unitData, infusion, excessKills));
            }
        }
 UnitCost GetRawUnitCost(UnitRecepePiece piece)
 {
     return(GetRawUnitCost(piece.Unit, piece.Infuse, piece.Rank, false));
 }