Пример #1
0
 public UnitTrainingPlan(UnitTrainingOrder order, Reason reason, int targetUnitTypeId = 0, int targetProvinceId = 0)
 {
     _unitTrainingOrder = order;
     _reason            = reason;
     _targetUnitTypeId  = targetUnitTypeId;
     _targetProvinceId  = targetProvinceId;
 }
Пример #2
0
 /// <summary>
 /// Add an order to the training queue
 /// </summary>
 /// <param name="unitType">The type of the unit to train</param>
 /// <param name="quantity">The number of units to train</param>
 /// <param name="standing">Whether the order is standing (repeating)</param>
 /// <returns>Whether the order was successfully processed</returns>
 public bool QueueTraining(UnitType unitType, int quantity, bool standing)
 {
     if (_owners.FundUnitTraining(unitType, quantity))
     {
         _trainingOrders[unitType] = new UnitTrainingOrder(unitType, quantity, standing);
         return(true);
     }
     return(false);
 }
Пример #3
0
    /// <summary>
    /// Prepare additional unit training plans by selecting the cheapest units
    /// taking into account the budget and the existing training plan, if any
    /// </summary>
    /// <param name="province">The province for which to prepare unit training plans</param>
    /// <param name="budget">The amount of money available for spending</param>
    /// <param name="existingPlan">The province's current training plan</param>
    /// <returns>List of unit training plans</returns>
    private List <UnitTrainingPlan> PlanTrainingFodder(Province province, int budget, ProvinceTrainingPlan existingPlan = null)
    {
        List <UnitTrainingPlan> result = new List <UnitTrainingPlan>();
        int manpower = province.GetRemainingManpower();

        if (existingPlan != null)
        {
            manpower -= existingPlan.GetManpowerCost();
        }

        // no recruits or no money => good buy!
        if (manpower <= 0 || budget <= 0)
        {
            return(result);
        }

        List <UnitType>            trainable     = province.GetCheapestToTrainUnits();
        Dictionary <UnitType, int> trainingOrder = new Dictionary <UnitType, int>();

        if (trainable.Count > 0)
        {
            if (trainable.Count == 1)
            {
                // simple - train this single cheapest unit
                trainingOrder[trainable[0]] = Mathf.Min(manpower, budget / trainable[0].GetTrainingCost());
            }
            else
            {
                // more complicated - select one of the options randomly
                for (int i = 0; i < trainable.Count; i++)
                {
                    trainingOrder[trainable[i]] = 0;
                }
                for (int i = 0; i < manpower; i++)
                {
                    int randomIndex = UnityEngine.Random.Range(0, trainable.Count);
                    trainingOrder[trainable[randomIndex]] += 1;
                    budget -= trainable[randomIndex].GetTrainingCost();
                    if (budget <= 0)
                    {
                        break;
                    }
                }
            }
        }

        foreach (KeyValuePair <UnitType, int> entry in trainingOrder)
        {
            if (entry.Value > 0)
            {
                UnitTrainingOrder order = new UnitTrainingOrder(entry.Key, entry.Value, false);
                result.Add(new UnitTrainingPlan(order, UnitTrainingPlan.Reason.FODDER));
            }
        }
        return(result);
    }
Пример #4
0
    /// <summary>
    /// Parse the province training plan and queue its training orders
    /// </summary>
    /// <param name="province">The province where to place the unit training order</param>
    /// <param name="plan">Province training plan to process</param>
    private void ProcessProvinceTrainingPlan(Province province, ProvinceTrainingPlan plan)
    {
        List <UnitTrainingPlan> unitPlans = plan.GetUnitTrainingPlans();

        for (int i = 0; i < unitPlans.Count; i++)
        {
            UnitTrainingOrder order    = unitPlans[i].GetUnitTrainingOrder();
            UnitType          unitType = order.GetUnitType();
            int quantity = order.GetQuantity();
            if (quantity > 0)
            {
                FileLogger.Trace("AI", "Queueing " + quantity + " " + unitType.GetName() + "s (" + unitPlans[i].GetReason() + ") in " + province.GetName());
                // re-evaluate training orders every turn, don't create standing training orders
                province.QueueTraining(unitType, quantity, false);
            }
        }
    }
Пример #5
0
    /// <summary>
    /// Prepare the province data for serialization
    /// </summary>
    public void PrepareForSerialization()
    {
        _data.units = new UnitData[_units.Count];
        for (int i = 0; i < _units.Count; i++)
        {
            _data.units[i] = new UnitData(_units[i].GetUnitType().GetId(), _units[i].GetQuantity());
        }

        List <UnitType> types = new List <UnitType>(_trainingOrders.Keys);

        _data.training = new UnitTrainingOrderData[types.Count];
        for (int i = 0; i < types.Count; i++)
        {
            UnitTrainingOrder order = _trainingOrders[types[i]];
            _data.training[i] = new UnitTrainingOrderData(types[i].GetId(), order.GetQuantity(), order.IsStanding());
        }
    }
Пример #6
0
    /// <summary>
    /// Revise training plans of the cheapest units based on the money left and the existing training plan, if available
    /// </summary>
    /// <param name="province">The province for which to prepare unit training plans</param>
    /// <param name="budget">The amount of money available for spending</param>
    /// <param name="existingPlan">The province's current training plan</param>
    private void UpgradeTrainingFodderPlan(Province province, int budget, ProvinceTrainingPlan existingPlan)
    {
        // no money => good buy!
        if (budget <= 0)
        {
            return;
        }

        List <UnitType>            trainable     = province.GetTrainableUnits();
        Dictionary <UnitType, int> trainingOrder = new Dictionary <UnitType, int>();
        List <UnitType>            fodder        = province.GetCheapestToTrainUnits();
        List <UnitType>            expensives    = new List <UnitType>();

        for (int i = 0; i < trainable.Count; i++)
        {
            if (!fodder.Contains(trainable[i]))
            {
                trainingOrder[trainable[i]] = 0;
                expensives.Add(trainable[i]);
            }
        }

        if (trainingOrder.Count > 0)
        {
            List <UnitTrainingPlan> plans = existingPlan.GetUnitTrainingPlans();
            for (int i = 0; i < plans.Count; i++)
            {
                if (plans[i].GetReason() == UnitTrainingPlan.Reason.FODDER)
                {
                    int manpower   = plans[i].GetManpowerCost();
                    int fodderCost = plans[i].GetUnitTypeTrainingCost();
                    for (int j = 0; j < manpower; j++)
                    {
                        int randomIndex  = UnityEngine.Random.Range(0, expensives.Count);
                        int costIncrease = expensives[randomIndex].GetTrainingCost() - fodderCost;
                        if (budget >= costIncrease)
                        {
                            trainingOrder[expensives[randomIndex]] += 1;
                            plans[i].DecreaseQuantity();
                            budget -= costIncrease;
                        }
                        if (budget <= 0)
                        {
                            break;
                        }
                    }
                }

                if (budget <= 0)
                {
                    break;
                }
            }

            List <UnitTrainingPlan> newPlans = new List <UnitTrainingPlan>();
            foreach (KeyValuePair <UnitType, int> entry in trainingOrder)
            {
                if (entry.Value > 0)
                {
                    UnitTrainingOrder order = new UnitTrainingOrder(entry.Key, entry.Value, false);
                    newPlans.Add(new UnitTrainingPlan(order, UnitTrainingPlan.Reason.CORE));
                }
            }
            if (newPlans.Count > 0)
            {
                existingPlan.AddUnitTrainingPlans(newPlans);
            }
        }

        return;
    }
Пример #7
0
    /// <summary>
    /// Prepare additional unit training plans based on the threats identified, the budget, and the existing training plan, if available
    /// </summary>
    /// <param name="province">The province for which to prepare unit training plans</param>
    /// <param name="dangers">Threats identified as a hash of enemy provice id => list of units</param>
    /// <param name="budget">The amount of money available for spending</param>
    /// <param name="existingPlan">The province's current training plan</param>
    /// <returns>List of unit training plans</returns>
    private List <UnitTrainingPlan> PlanTrainingCounters(Province province, Dictionary <int, List <Unit> > dangers, int budget, ProvinceTrainingPlan existingPlan = null)
    {
        List <UnitTrainingPlan> result = new List <UnitTrainingPlan>();
        int manpower = province.GetRemainingManpower();

        if (existingPlan != null)
        {
            manpower -= existingPlan.GetManpowerCost();
        }

        // no dangers, no recruits or no money => good buy!
        if (dangers.Count == 0 || manpower <= 0 || budget <= 0)
        {
            return(result);
        }

        List <UnitType> trainable = province.GetTrainableUnits();
        List <Unit>     units     = new List <Unit>();

        for (int i = 0; i < trainable.Count; i++)
        {
            units.Add(new Unit(trainable[i], 1));
        }

        List <int> targets = new List <int>(dangers.Keys);

        for (int i = 0; i < targets.Count; i++)
        {
            List <Unit> localDangers = dangers[targets[i]];
            for (int j = 0; j < localDangers.Count; j++)
            {
                Unit counter = CombatHelper.Instance.GetAttackingCounter(localDangers[j], units);
                if (counter != null)
                {
                    int cost     = counter.GetUnitType().GetTrainingCost();
                    int quantity = Math.Min(budget / cost, Math.Min(province.GetRemainingManpower(), localDangers[j].GetQuantity() / 2));
                    if (quantity > 0)
                    {
                        localDangers[j].AddQuantity(-quantity);
                        UnitTrainingOrder order = new UnitTrainingOrder(counter.GetUnitType(), quantity, false);
                        result.Add(new UnitTrainingPlan(order, UnitTrainingPlan.Reason.COUNTER, localDangers[j].GetUnitType().GetId(), targets[i]));
                        manpower -= quantity;
                        budget   -= cost * quantity;

                        FileLogger.Trace("AI", counter.GetUnitType().GetName() + " is an attacking counter to " + localDangers[j].GetUnitType().GetName());
                    }
                    if (manpower <= 0 || budget <= 0)
                    {
                        return(result);
                    }
                }
                counter = CombatHelper.Instance.GetDefendingCounter(localDangers[j], units);
                if (counter != null)
                {
                    int cost     = counter.GetUnitType().GetTrainingCost();
                    int quantity = Math.Min(budget / cost, Math.Min(province.GetRemainingManpower(), localDangers[j].GetQuantity()));
                    if (quantity > 0)
                    {
                        localDangers[j].AddQuantity(-quantity);
                        UnitTrainingOrder order = new UnitTrainingOrder(counter.GetUnitType(), quantity, false);
                        result.Add(new UnitTrainingPlan(order, UnitTrainingPlan.Reason.COUNTER, localDangers[j].GetUnitType().GetId(), targets[i]));
                        manpower -= quantity;
                        budget   -= cost * quantity;
                        FileLogger.Trace("AI", counter.GetUnitType().GetName() + " is an defending counter to " + localDangers[j].GetUnitType().GetName());
                    }
                    if (manpower <= 0 || budget <= 0)
                    {
                        return(result);
                    }
                }
            }
        }
        return(result);
    }
Пример #8
0
    /// <summary>
    /// Class constructor
    /// </summary>
    /// <param name="data">Province data loaded from a save</param>
    /// <param name="dwellers">Race that populates the province</param>
    /// <param name="owners">Faction that owns the province</param>
    /// <param name="allUnitTypes">A hash of id => unit type that includes all unit types in the game</param>
    public Province(ProvinceData data, Race dwellers, Faction owners, Dictionary <int, UnitType> allUnitTypes)
    {
        _data     = data;
        _dwellers = dwellers;
        _owners   = owners;

        if (_data.raceId != dwellers.GetId())
        {
            Debug.Log("Bad race data for province " + _data.id + ": " + _data.raceId + " is changed to " + dwellers.GetId());
            _data.raceId = dwellers.GetId();
        }

        if (_data.factionId != owners.GetId())
        {
            Debug.Log("Bad faction data for province " + _data.id + ": " + _data.factionId + " is changed to " + owners.GetId());
            _data.factionId = owners.GetId();
        }

        _neighbors = new List <Province>();

        _units = new List <Unit>();
        for (int i = 0; i < data.units.Length; i++)
        {
            _units.Add(new Unit(data.units[i], allUnitTypes[data.units[i].id]));
        }

        _trainingOrders = new Dictionary <UnitType, UnitTrainingOrder>();
        if (data.training != null && data.training.Length > 0)
        {
            for (int i = 0; i < data.training.Length; i++)
            {
                UnitTrainingOrderData order = data.training[i];
                // order.id is unit type id just for conspiration
                UnitType unitType = allUnitTypes[order.id];
                _trainingOrders[unitType] = new UnitTrainingOrder(order, allUnitTypes);
            }
        }

        _trainable = new List <UnitType>();
        int minTrainingCost = 100500; // means "a lot"

        // if the province doesn't have defined trainable unit types, use the list of racial units
        if (_data.trainable == null || _data.trainable.Length == 0)
        {
            List <UnitType> racialUnits = _dwellers.GetRacialUnits();
            for (int i = 0; i < racialUnits.Count; i++)
            {
                // heroes can't be trained
                if (racialUnits[i].IsTrainable())
                {
                    _trainable.Add(racialUnits[i]);
                    if (!racialUnits[i].IsHoly())
                    {
                        minTrainingCost = Math.Min(minTrainingCost, racialUnits[i].GetTrainingCost());
                    }
                }
            }
        }
        else
        {
            for (int i = 0; i < _data.trainable.Length; i++)
            {
                UnitType unitType = allUnitTypes[_data.trainable[i]];
                if (unitType != null && unitType.IsTrainable())
                {
                    _trainable.Add(unitType);
                    if (!unitType.IsHoly())
                    {
                        minTrainingCost = Math.Min(minTrainingCost, unitType.GetTrainingCost());
                    }
                }
            }
        }

        SelectCheapestToTrainUnits(minTrainingCost);
    }