Example #1
0
        static float evaluateAssignments(Dictionary <AbstractActor, UnitRole> unitAssignments, List <AbstractActor> allUnits, Dictionary <UnitRoleAssignmentRecord, float> roleAssignmentDictionary)
        {
            float penalty = getLegalTeamCountPenalty(countRolesAfterAssignment(unitAssignments, allUnits), allUnits);

            if (penalty > 0)
            {
                return(-penalty);
            }

            float score = 0.0f;

            for (int unitIndex = 0; unitIndex < allUnits.Count; ++unitIndex)
            {
                AbstractActor unit = allUnits[unitIndex];
                UnitRole      role = unit.DynamicUnitRole;
                if ((unitAssignments != null) && (unitAssignments.ContainsKey(unit)))
                {
                    role = unitAssignments[unit];
                }

                UnitRoleAssignmentRecord assignmentRecord = new UnitRoleAssignmentRecord(unit, role);
                // might not actually be there, e.g. if the unit is currently unassigned.
                if (roleAssignmentDictionary.ContainsKey(assignmentRecord))
                {
                    score += roleAssignmentDictionary[assignmentRecord];
                }
            }
            return(score);
        }
Example #2
0
        public static void AssignRoleToUnit(AbstractActor unit, List <AbstractActor> otherUnits)
        {
            if (unit.BehaviorTree.HasPriorityTargets() ||
                (!unit.BehaviorTree.GetBehaviorVariableValue(BehaviorVariableName.Bool_UseDynamicLanceRoles).BoolVal))
            {
                // don't assign dynamic roles when there's a priority target
                unit.DynamicUnitRole = UnitRole.Undefined;
                return;
            }

            if ((unit.StaticUnitRole == UnitRole.Turret) || (unit.StaticUnitRole == UnitRole.Vehicle && (!UnitIsECMRole(unit) && !UnitIsActiveProbe(unit))))
            {
                // don't assign roles to turrets or vehicles, except if they are ECM vehicles - Allie
                return;
            }

            //Debug.Log("trying to assign role to " + unit.DisplayName);
            otherUnits = otherUnits.FindAll(x => (x != unit) &&
                                            (x.StaticUnitRole != UnitRole.Turret) &&
                                            (x.StaticUnitRole != UnitRole.Vehicle) &&
                                            (!x.IsDead));

            //Debug.Log("other unit count: " + otherUnits.Count);

            // and now a list of the other interesing units plus our selected unit
            List <AbstractActor> allUnits = new List <AbstractActor>();

            allUnits.Add(unit);
            for (int unitIndex = 0; unitIndex < otherUnits.Count; ++unitIndex)
            {
                allUnits.Add(otherUnits[unitIndex]);
            }

            // OK So we do want to give an ECM Carrier role to ECM carrying vehicles.. - Allie
            if (unit.StaticUnitRole == UnitRole.Vehicle)
            {
                Dictionary <AbstractActor, UnitRole> assignmentDict = new Dictionary <AbstractActor, UnitRole>();
                if (UnitIsEWE(unit))
                {
                    assignmentDict[unit] = UnitRole.Ewe;
                }
                else if (UnitIsECMRole(unit))
                {
                    assignmentDict[unit] = UnitRole.EcmCarrier;
                }
                else if (UnitIsActiveProbe(unit))
                {
                    assignmentDict[unit] = UnitRole.ActiveProbe;
                }
                else
                {
                    return;
                }

                applyAssignments(assignmentDict, allUnits, true);
                return;
            }

            // lastManStanding is its own thing (sigh)
            if (UnitIsLastManStandingRole(unit))
            {
                Dictionary <AbstractActor, UnitRole> assignmentDict = new Dictionary <AbstractActor, UnitRole>();
                assignmentDict[unit] = UnitRole.LastManStanding;
                applyAssignments(assignmentDict, allUnits);
                return;
            }

            // noncombatant units are their own thing (sigh)
            if (UnitIsNonCombatantRole(unit))
            {
                Dictionary <AbstractActor, UnitRole> assignmentDict = new Dictionary <AbstractActor, UnitRole>();
                assignmentDict[unit] = UnitRole.NonCombatant;
                applyAssignments(assignmentDict, allUnits);
                return;
            }

            // melee only units are their own thing (sigh)
            if (UnitIsMeleeOnlyRole(unit))
            {
                Dictionary <AbstractActor, UnitRole> assignmentDict = new Dictionary <AbstractActor, UnitRole>();
                assignmentDict[unit] = UnitRole.MeleeOnly;
                applyAssignments(assignmentDict, allUnits);
                return;
            }

            if (UnitIsEWE(unit))
            {
                Dictionary <AbstractActor, UnitRole> assignmentDict = new Dictionary <AbstractActor, UnitRole>();
                assignmentDict[unit] = UnitRole.Ewe;
                applyAssignments(assignmentDict, allUnits);
                return;
            }

            if (UnitIsActiveProbe(unit))
            {
                Dictionary <AbstractActor, UnitRole> assignmentDict = new Dictionary <AbstractActor, UnitRole>();
                assignmentDict[unit] = UnitRole.ActiveProbe;
                applyAssignments(assignmentDict, allUnits);
                return;
            }

            if (UnitIsECMRole(unit))
            {
                Dictionary <AbstractActor, UnitRole> assignmentDict = new Dictionary <AbstractActor, UnitRole>();
                assignmentDict[unit] = UnitRole.EcmCarrier;
                applyAssignments(assignmentDict, allUnits);
                return;
            }


            // scouts are their own thing (sigh)
            if (UnitMustBeScout(unit))
            {
                Dictionary <AbstractActor, UnitRole> assignmentDict = new Dictionary <AbstractActor, UnitRole>();
                assignmentDict[unit] = UnitRole.Scout;
                applyAssignments(assignmentDict, allUnits);
                return;
            }

            // first check to see if we're meeting our minimums. e.g. at startup, we won't.
            if (!unitsMeetMinimums(allUnits))
            {
                fillOutMinimums(allUnits);
            }

            List <Dictionary <AbstractActor, UnitRole> > possibleAssignments = new List <Dictionary <AbstractActor, UnitRole> >();

            UnitRole[] dynamicRoles =
            {
                UnitRole.Brawler,
                UnitRole.Sniper,
                // UnitRole.Scout,   // scouts don't use the normal evaluation routines
            };

            // do the raw evaluation, without considering role tags
            Dictionary <UnitRoleAssignmentRecord, float> unNormalizedRoleEvaluations = new Dictionary <UnitRoleAssignmentRecord, float>();

            for (int unitIndex = 0; unitIndex < allUnits.Count; ++unitIndex)
            {
                AbstractActor assignUnit = allUnits[unitIndex];
                for (int roleIndex = 0; roleIndex < dynamicRoles.Length; ++roleIndex)
                {
                    UnitRole assignRole = dynamicRoles[roleIndex];

                    UnitRoleAssignmentRecord assignmentRecord = new UnitRoleAssignmentRecord(assignUnit, assignRole);
                    float evaluation = EvaluateAssignmentForUnit(assignUnit, assignRole);
                    unNormalizedRoleEvaluations[assignmentRecord] = evaluation;
                }
            }

            // normalize the evaluations across roles, so that 0.0 is the worst brawler and 1.0 is the best
            // do the raw evaluation, without considering role tags
            Dictionary <UnitRoleAssignmentRecord, float> normalizedRoleEvaluations = new Dictionary <UnitRoleAssignmentRecord, float>();

            for (int roleIndex = 0; roleIndex < dynamicRoles.Length; ++roleIndex)
            {
                UnitRole assignRole = dynamicRoles[roleIndex];

                float maxValue = float.MinValue;
                float minValue = float.MaxValue;

                for (int unitIndex = 0; unitIndex < allUnits.Count; ++unitIndex)
                {
                    AbstractActor assignUnit = allUnits[unitIndex];
                    float         val        = unNormalizedRoleEvaluations[new UnitRoleAssignmentRecord(assignUnit, assignRole)];
                    maxValue = Mathf.Max(maxValue, val);
                    minValue = Mathf.Min(minValue, val);
                }
                float valueRange = maxValue - minValue;
                for (int unitIndex = 0; unitIndex < allUnits.Count; ++unitIndex)
                {
                    AbstractActor assignUnit = allUnits[unitIndex];
                    float         val        = unNormalizedRoleEvaluations[new UnitRoleAssignmentRecord(assignUnit, assignRole)];

                    float normalized = valueRange == 0.0f ? 1.0f : (val - minValue) / valueRange;

                    normalizedRoleEvaluations[new UnitRoleAssignmentRecord(assignUnit, assignRole)] = normalized;
                }
            }

            // now add in the role tag multipliers
            Dictionary <UnitRoleAssignmentRecord, float> normalizedRoleEvaluationsWithTagMultipliers = new Dictionary <UnitRoleAssignmentRecord, float>();

            for (int roleIndex = 0; roleIndex < dynamicRoles.Length; ++roleIndex)
            {
                UnitRole assignRole = dynamicRoles[roleIndex];

                for (int unitIndex = 0; unitIndex < allUnits.Count; ++unitIndex)
                {
                    AbstractActor            assignUnit       = allUnits[unitIndex];
                    UnitRoleAssignmentRecord assignmentRecord = new UnitRoleAssignmentRecord(assignUnit, assignRole);
                    float val    = normalizedRoleEvaluations[assignmentRecord];
                    float scaled = val * getRoleTagMultiplierForUnit(assignUnit, assignRole);
                    normalizedRoleEvaluationsWithTagMultipliers[assignmentRecord] = scaled;
                }
            }


            // first, consider just assigning this unit to a new role (abandoning the old role)
            for (int roleIndex = 0; roleIndex < dynamicRoles.Length; ++roleIndex)
            {
                UnitRole newRole = dynamicRoles[roleIndex];
                if (newRole == unit.DynamicUnitRole)
                {
                    continue;
                }

                Dictionary <AbstractActor, UnitRole> newAssignment = new Dictionary <AbstractActor, UnitRole>();
                newAssignment[unit] = newRole;
                //Debug.LogFormat("Assignment {0} abandonOld", possibleAssignments.Count);
                //Debug.LogFormat("Assigning {0} to role {1})", unit.DisplayName, newRole);
                possibleAssignments.Add(newAssignment);
            }

            // now, try swapping with each of the other units
            if (unit.DynamicUnitRole != UnitRole.Undefined)
            {
                for (int otherUnitIndex = 0; otherUnitIndex < otherUnits.Count; ++otherUnitIndex)
                {
                    AbstractActor otherUnit = otherUnits[otherUnitIndex];
                    if ((otherUnit.DynamicUnitRole == unit.DynamicUnitRole) || (otherUnit.DynamicUnitRole == UnitRole.Undefined))
                    {
                        // can't swap with someone who's the same as me, and don't want to swap with an undefined role
                        continue;
                    }

                    Dictionary <AbstractActor, UnitRole> newAssignment = new Dictionary <AbstractActor, UnitRole>();
                    newAssignment[unit]      = otherUnit.DynamicUnitRole;
                    newAssignment[otherUnit] = unit.DynamicUnitRole;
                    //Debug.LogFormat("Assignment {0} swap", possibleAssignments.Count);
                    //Debug.LogFormat("Assigning {0} to role {1}", unit.DisplayName, otherUnit.DynamicUnitRole);
                    //Debug.LogFormat("Assigning {0} to role {1}", otherUnit.DisplayName, unit.DynamicUnitRole);
                    possibleAssignments.Add(newAssignment);
                }
            }

            // now, iterate over all the possible assignements and find the one with the highest value

            float bestNonPenaltyEvaluationScore = float.MinValue;
            int   bestNonPenaltyIndex           = -1;

            float bestPenaltyEvaluationScore = float.MinValue;
            int   bestPenaltyIndex           = -1;

            for (int assignmentIndex = 0; assignmentIndex < possibleAssignments.Count; ++assignmentIndex)
            {
                float assignmentEvaluationScore = evaluateAssignments(possibleAssignments[assignmentIndex], allUnits, normalizedRoleEvaluationsWithTagMultipliers);

                if (assignmentEvaluationScore > 0.0f)
                {
                    if (assignmentEvaluationScore > bestNonPenaltyEvaluationScore)
                    {
                        bestNonPenaltyIndex           = assignmentIndex;
                        bestNonPenaltyEvaluationScore = assignmentEvaluationScore;
                    }
                }
                else
                {
                    if (assignmentEvaluationScore > bestPenaltyEvaluationScore)
                    {
                        bestPenaltyIndex           = assignmentIndex;
                        bestPenaltyEvaluationScore = assignmentEvaluationScore;
                    }
                }
            }

            float statusQuoEvaluationScore = evaluateAssignments(null, allUnits, normalizedRoleEvaluationsWithTagMultipliers);

            bool isUnassigned = unit.DynamicUnitRole == UnitRole.Undefined;

            if (bestNonPenaltyIndex >= 0)
            {
                float ratio = statusQuoEvaluationScore <= 0 ? float.MaxValue : (bestNonPenaltyEvaluationScore - statusQuoEvaluationScore) / statusQuoEvaluationScore;

                if (isUnassigned || (ratio > unit.Combat.Constants.DynamicAIRoleConstants.hysteresis))
                {
                    //Debug.LogFormat("applying {0} nonpenalty", bestNonPenaltyIndex);
                    applyAssignments(possibleAssignments[bestNonPenaltyIndex], allUnits);
                }
            }
            else
            {
                if (isUnassigned || (bestPenaltyEvaluationScore > statusQuoEvaluationScore))
                {
                    //Debug.LogFormat("applying {0} penalty", bestPenaltyIndex);
                    applyAssignments(possibleAssignments[bestPenaltyIndex], allUnits);
                }
            }
            if (unit.DynamicUnitRole == UnitRole.Undefined)
            {
                Debug.LogError("Dynamic Role Assignment: chose to leave unit undefined");
                Debug.LogError("bestNonPenaltyIndex: " + bestNonPenaltyIndex);
                Debug.LogError("bestNonPenaltyEvaluationScore: " + bestNonPenaltyEvaluationScore);
                Debug.LogError("bestPenaltyIndex: " + bestPenaltyIndex);
                Debug.LogError("bestPenaltyEvaluationScore: " + bestPenaltyEvaluationScore);
            }
        }