예제 #1
0
        private double AdjustStat(UnitBuilder unit, double valueBudget, UnitStat stat)
        {
            switch (stat)
            {
            case UnitStat.Health:
                return(AdjustHealthStat(unit, valueBudget));

            case UnitStat.Armor:
                return(AdjustArmorStat(unit, valueBudget));

            case UnitStat.Cost:
                return(AdjustCostStat(unit, valueBudget));

            case UnitStat.BuildTime:
                return(AdjustBuildTimeStat(unit, valueBudget));

            case UnitStat.Supply:
                return(AdjustSupplyCostStat(unit, valueBudget));

            case UnitStat.MoveRange:
                return(AdjustMoveRangeStat(unit, valueBudget));

            default:
                return(0);
            }
        }
예제 #2
0
        private double AdjustStats(UnitBuilder unit, double valueBudget)
        {
            var remainingBudget = valueBudget;
            var statsInOrder    = unitStatValues.ToRandomQueue(Random);

            var allocatedAny = false;

            while (allocatedAny)
            {
                allocatedAny = false;

                foreach (var stat in statsInOrder)
                {
                    var statBudget = Math.Abs(remainingBudget) > 0.1
                        ? remainingBudget * Random.NextDouble(0.25, 0.65)
                        : remainingBudget;

                    var adjustment = AdjustStat(unit, statBudget, stat);
                    if (adjustment != 0)
                    {
                        allocatedAny = true;
                    }

                    remainingBudget -= adjustment;
                }
            }

            return(valueBudget - remainingBudget);
        }
예제 #3
0
        private void GenerateSupportCaster(UnitBuilder unit, double remainingValue)
        {
            // buy back value by reducing health
            remainingValue -= AdjustHealthStat(unit, -remainingValue * Random.NextDouble(0.15, 0.55));

            // either three support abilities or two support plus one offensive
            remainingValue -= AddFeature(unit, SelectDefensiveAbility, remainingValue * Random.NextDouble(0.2, 0.5));

            remainingValue -= AddFeature(unit, SelectDefensiveAbility, remainingValue * Random.NextDouble(0.3, 0.7));

            if (Random.Next(2) == 0)
            {
                remainingValue -= AddFeature(unit, SelectOffensiveAbility, remainingValue * Random.NextDouble(0.5, 0.8));
            }
            else
            {
                remainingValue -= AddFeature(unit, SelectDefensiveAbility, remainingValue * Random.NextDouble(0.5, 0.8));
            }

            // plus either make it a detector or give it an attack.
            if (Random.Next(2) == 0)
            {
                unit.IsDetector = true;
            }
            else
            {
                remainingValue -= AddFeature(unit, SelectAttack, remainingValue * Random.NextDouble(0.75, 1));
            }

            AdjustStats(unit, remainingValue);
        }
예제 #4
0
        protected void GenerateUnits(List <UnitBuilder> unitsTreeOrder)
        {
            // get a queue of all units, in a random order
            var units = Units.Values
                        .ToArray()
                        .ToRandomQueue(Random);

            var allRoles = Enum.GetValues(typeof(UnitRole))
                           .Cast <UnitRole>()
                           .ToList();

            allRoles.Randomize(Random);

            while (true)
            {
                // Populate every role once, as long as we have units to populate.
                foreach (var role in allRoles)
                {
                    if (units.Count == 0)
                    {
                        return;
                    }

                    UnitBuilder unit = units.Dequeue();

                    var techProgressionFraction = (float)unitsTreeOrder.IndexOf(unit) / unitsTreeOrder.Count;
                    var unitValue = BaseUnitValue + (MaxUnitValue - BaseUnitValue) * techProgressionFraction;

                    GenerateUnit(unit, role, unitValue, techProgressionFraction);
                }
            }
        }
예제 #5
0
        private void GenerateUnit(UnitBuilder unit, UnitRole role, double value, double techProgressionFraction)
        {
            unit.AllocateName(UsedNames);

            unit.VisionRange = UnitVisionRange;

            unit.MoveRange = BaseUnitMoveRange;

            // standard health, armor, mana, cost, supply cost and build time values for its value

            unit.BuildTime = Math.Max(1, Random.Next(value * 0.75, value * 0.95));

            var overallCost = (int)value * Random.Next(25, 40);

            unit.Cost = SplitResourceCosts(overallCost, techProgressionFraction);

            unit.Cost[GameModels.Definitions.ResourceType.Supply] = Math.Max(1, Random.Next(value * 0.75, value * 0.95));

            unit.Health = Random.Next(value * 20, value * 35)
                          .RoundNearest(5);

            unit.Mana = Random.Next(value * 40, value * 60)
                        .RoundNearest(5);

            unit.Armor = Random.Next(value * 0.25, value * 0.9);

            switch (role)
            {
            case UnitRole.AllRounder:
            default:
                unit.Mana = 0;
                GenerateAllRounder(unit, value);
                break;

            case UnitRole.DamageDealer:
                unit.Mana = 0;
                GenerateDamageDealer(unit, value);
                break;

            case UnitRole.Scout:
                unit.Mana = 0;
                GenerateScout(unit, value);
                break;

            case UnitRole.MeatShield:
                unit.Mana = 0;
                GenerateMeatShield(unit, value);
                break;

            case UnitRole.SupportCaster:
                GenerateSupportCaster(unit, value);
                break;

            case UnitRole.OffensiveCaster:
                GenerateOffensiveCaster(unit, value);
                break;
            }
        }
예제 #6
0
        private double AdjustHealthStat(UnitBuilder unit, double valueBudget)
        {
            var fullConversionGain = valueBudget / ValuePerHealth;
            var actualGain         = fullConversionGain.RoundNearestDown(5);
            var actualSpend        = actualGain * ValuePerHealth;

            unit.Health += actualGain;

            return(actualSpend);
        }
예제 #7
0
        private double AdjustArmorStat(UnitBuilder unit, double valueBudget)
        {
            var fullConversionGain = valueBudget / ValuePerArmor;
            var actualGain         = fullConversionGain.RoundNearestDown(1);
            var actualSpend        = actualGain * ValuePerArmor;

            unit.Armor += actualGain;

            return(actualSpend);
        }
예제 #8
0
        private double AdjustMoveRangeStat(UnitBuilder unit, double valueBudget)
        {
            var fullConversionGain = valueBudget / ValuePerMoveRange;
            var actualGain         = fullConversionGain.RoundNearestDown(1);

            var actualSpend = actualGain * ValuePerMoveRange;

            unit.MoveRange += actualGain;

            return(actualSpend);
        }
예제 #9
0
        private double AddFeature(UnitBuilder unit, FeatureSelector selectFeature, double valueBudget)
        {
            var feature = selectFeature(ref valueBudget);

            if (feature == null)
            {
                return(0);
            }

            unit.Features.Add(feature);
            return(valueBudget);
        }
예제 #10
0
        private double AdjustCostStat(UnitBuilder unit, double valueBudget)
        {
            var fullConversionGain = valueBudget / ValuePerCostMultiplierIncrement;
            var actualGain         = fullConversionGain.RoundNearestDown(1);
            var actualSpend        = actualGain * ValuePerCostMultiplierIncrement;

            foreach (var cost in unit.Cost.ToArray())
            {
                if (cost.Key != ResourceType.Supply)
                {
                    unit.Cost[cost.Key] = cost.Value * -actualGain;
                }
            }

            return(actualSpend);
        }
예제 #11
0
        private void GenerateScout(UnitBuilder unit, double remainingValue)
        {
            // give it a fairly weak attack
            remainingValue -= AddFeature(unit, SelectAttack, remainingValue * Random.NextDouble(0.15, 0.25));

            // buy back value by reducing health
            remainingValue -= AdjustHealthStat(unit, -remainingValue * Random.NextDouble(0.1, 0.35));

            // a big speed boost
            remainingValue -= AdjustMoveRangeStat(unit, remainingValue * Random.NextDouble(0.35, 0.7));

            // and a utility ability
            remainingValue -= AddFeature(unit, SelectUtility, remainingValue * Random.NextDouble(0.75, 1));

            AdjustStats(unit, remainingValue);
        }
예제 #12
0
        private void GenerateAllRounder(UnitBuilder unit, double remainingValue)
        {
            // Spend roughly half its value on an attack
            remainingValue -= AddFeature(unit, SelectAttack, remainingValue * Random.NextDouble(0.35, 0.55));

            // Spend roughly half of the remainder on a utility ability.
            remainingValue -= AddFeature(unit, SelectUtility, remainingValue * Random.NextDouble(0.25, 0.65));

            // Spend the remainder on 2-3 stat boosts ... health, armor, speed, reduced cost, reduced build time
            remainingValue -= AdjustRandomStat(unit, remainingValue * Random.NextDouble(0.3, 0.6));

            if (Random.Next(3) == 0)
            {
                remainingValue -= AdjustRandomStat(unit, remainingValue * Random.NextDouble(0.3, 0.6));
            }

            AdjustStats(unit, remainingValue);
        }
예제 #13
0
        private void GenerateDamageDealer(UnitBuilder unit, double remainingValue)
        {
            // spend most of its value on an attack
            remainingValue -= AddFeature(unit, SelectAttack, remainingValue * Random.NextDouble(0.65, 0.85));

            // buy back value by reducing health
            remainingValue -= AdjustHealthStat(unit, -remainingValue * Random.NextDouble(0.7, 1.5));

            // spend remaining value on an offensive ability, or a utility (less likely)
            if (Random.Next(4) == 0)
            {
                remainingValue -= AddFeature(unit, SelectUtility, remainingValue);
            }
            else
            {
                remainingValue -= AddFeature(unit, SelectOffensiveAbility, remainingValue);
            }

            AdjustStats(unit, remainingValue);
        }
예제 #14
0
        private double AdjustBuildTimeStat(UnitBuilder unit, double valueBudget)
        {
            var fullConversionGain = valueBudget / ValuePerBuildTimeReduction;
            var actualGain         = fullConversionGain.RoundNearestDown(1);

            if (actualGain >= unit.BuildTime)
            {
                actualGain = unit.BuildTime - 1;
            }

            if (actualGain <= 0)
            {
                return(0);
            }

            var actualSpend = actualGain * ValuePerBuildTimeReduction;

            unit.BuildTime -= actualGain;

            return(actualSpend);
        }
예제 #15
0
        private void GenerateMeatShield(UnitBuilder unit, double remainingValue)
        {
            // give it an attack
            remainingValue -= AddFeature(unit, SelectAttack, remainingValue * Random.NextDouble(0.2, 0.45));

            // boost its health and armor
            remainingValue -= AdjustHealthStat(unit, remainingValue * Random.NextDouble(0.35, 0.65));
            remainingValue -= AdjustArmorStat(unit, remainingValue * Random.NextDouble(0.4, 0.6));

            // plus a random ability
            if (Random.Next(2) == 0)
            {
                remainingValue -= AddFeature(unit, SelectUtility, remainingValue);
            }
            else
            {
                remainingValue -= AddFeature(unit, SelectOffensiveAbility, remainingValue);
            }

            AdjustStats(unit, remainingValue);
        }
예제 #16
0
        private double AdjustSupplyCostStat(UnitBuilder unit, double valueBudget)
        {
            var fullConversionGain = valueBudget / ValuePerSupplyCostReduction;
            var actualGain         = fullConversionGain.RoundNearestDown(1);

            if (actualGain >= unit.Cost[ResourceType.Supply])
            {
                actualGain = unit.Cost[ResourceType.Supply] - 1;
            }

            if (actualGain <= 0)
            {
                return(0);
            }

            var actualSpend = actualGain * ValuePerSupplyCostReduction;

            unit.Cost[ResourceType.Supply] -= actualGain;

            return(actualSpend);
        }
예제 #17
0
        private void GenerateOffensiveCaster(UnitBuilder unit, double remainingValue)
        {
            // two offensive abilities plus one support or utility
            remainingValue -= AddFeature(unit, SelectOffensiveAbility, remainingValue * Random.NextDouble(0.2, 0.5));

            remainingValue -= AddFeature(unit, SelectOffensiveAbility, remainingValue * Random.NextDouble(0.3, 0.7));

            if (Random.Next(2) == 0)
            {
                remainingValue -= AddFeature(unit, SelectUtility, remainingValue * Random.NextDouble(0.7, 0.9));
            }
            else
            {
                remainingValue -= AddFeature(unit, SelectDefensiveAbility, remainingValue * Random.NextDouble(0.7, 0.9));
            }

            // and possibly give it a weak attack
            if (Random.Next(3) == 0)
            {
                remainingValue -= AddFeature(unit, SelectAttack, remainingValue * Random.NextDouble(0.85, 1));
            }

            AdjustStats(unit, remainingValue);
        }
예제 #18
0
        private double AdjustRandomStat(UnitBuilder unit, double valueBudget)
        {
            var randomStat = unitStatValues[Random.Next(unitStatValues.Length)];

            return(AdjustStat(unit, valueBudget, randomStat));
        }