public BehaviorVariableValue getBehaviourVariable(AbstractActor actor, BehaviorVariableName name)
 {
     try
     {
         List <BehaviorVariableScope> tags = getActorTags(actor);
         if (tags != null)
         {
             foreach (BehaviorVariableScope roleScope in tags)
             {
                 BehaviorVariableValue roleValue = roleScope.GetVariableWithMood(name, actor.BehaviorTree.mood);
                 if (roleValue != null)
                 {
                     if (Main.settings.debug)
                     {
                         Main.modLog.DebugMessage($"Hit for Var: {name.ToString()}, {actor.uid}({actor.Description.Id})");
                     }
                     return(roleValue);
                 }
             }
             if (Main.settings.debug)
             {
                 Main.modLog.DebugMessage($"Miss for Var: {name.ToString()}, {actor.uid}({actor.Description.Id})");
             }
         }
     }
     catch (Exception ex)
     {
         Main.modLog.LogException(ex);
     }
     return((BehaviorVariableValue)null);
 }
示例#2
0
    public static string StayInsideRegionGUID(AbstractActor unit)
    {
        BehaviorVariableValue variableValue = unit.BehaviorTree.GetBehaviorVariableValue(BehaviorVariableName.String_StayInsideRegionGUID);

        if ((variableValue == null) || (variableValue.StringVal.Length == 0))
        {
            return(string.Empty);
        }
        return(variableValue.StringVal);
    }
        static void logBVsForScope(string scopeName, BehaviorVariableScope scope)
        {
            logger.Log(string.Format(" ** Behavior variables on the {0} **", scopeName));
            List <BehaviorVariableName> variables = scope.VariableNames;

            for (int bvIndex = 0; bvIndex < variables.Count; ++bvIndex)
            {
                BehaviorVariableValue bvv = scope.GetVariable(variables[bvIndex]);
                logger.Log(bvToString(variables[bvIndex], bvv));
            }
        }
    override protected BehaviorTreeResults Tick()
    {
        BehaviorVariableValue variableValue = tree.GetBehaviorVariableValue(BehaviorVariableName.String_RouteGUID);

        if (variableValue == null)
        {
            Debug.Log("No behavior variable for patrol route GUID found");
            return(new BehaviorTreeResults(BehaviorNodeState.Failure));
        }

        string         patrolRouteGUID = variableValue.StringVal;
        RouteGameLogic route           = RoutingUtil.FindRouteByGUID(tree, patrolRouteGUID);

        if (route == null)
        {
            Debug.Log("No route matching GUID found");
            return(new BehaviorTreeResults(BehaviorNodeState.Failure));
        }

        if (unit.lance == null)
        {
            Debug.Log("No lance for this unit found");
            return(new BehaviorTreeResults(BehaviorNodeState.Failure));
        }

        BehaviorVariableValue closestPointBV = tree.GetBehaviorVariableValue(BehaviorVariableName.Bool_RouteStartAtClosestPoint);
        BehaviorVariableValue forwardBV      = tree.GetBehaviorVariableValue(BehaviorVariableName.Bool_RouteFollowingForward);

        int routeTargetPoint = 0;

        if (closestPointBV.BoolVal)
        {
            routeTargetPoint = closestPointOnRouteToLance(route, unit.lance);
        }
        else
        {
            if (forwardBV.BoolVal)
            {
                routeTargetPoint = 0;
            }
            else
            {
                routeTargetPoint = route.routePointList.Length - 1;
            }
        }
        unit.lance.BehaviorVariables.SetVariable(BehaviorVariableName.Int_RouteTargetPoint, new BehaviorVariableValue(routeTargetPoint));
        unit.lance.BehaviorVariables.SetVariable(BehaviorVariableName.Bool_RouteStarted, new BehaviorVariableValue(true));
        unit.lance.BehaviorVariables.SetVariable(BehaviorVariableName.Bool_RouteCompleted, new BehaviorVariableValue(false));
        unit.lance.BehaviorVariables.SetVariable(BehaviorVariableName.Bool_RouteFollowingForward, new BehaviorVariableValue(forwardBV.BoolVal));

        return(new BehaviorTreeResults(BehaviorNodeState.Success));
    }
    RouteGameLogic getRoute()
    {
        BehaviorVariableValue variableValue = tree.GetBehaviorVariableValue(BehaviorVariableName.String_RouteGUID);

        if (variableValue == null)
        {
            // no route
            AIUtil.LogAI("No behavior variable for route GUID found");
            return(null);
        }

        string routeGUID = variableValue.StringVal;

        return(RoutingUtil.FindRouteByGUID(tree, routeGUID));
    }
示例#6
0
        // TODO: Support global scopes [pilot personality, unit role, ai skill] on a later release
        // NOTE: Only supporting unit and lance to start with
        public BehaviorVariableValue GetBehaviourVariableValue(string type, string ownerGuid, string key)
        {
            if (this.customBehaviourVariables.ContainsKey(type))
            {
                Dictionary <string, CustomBehaviorVariableScope> typeScopes = this.customBehaviourVariables[type];
                if (typeScopes.ContainsKey(ownerGuid))
                {
                    CustomBehaviorVariableScope customScope = typeScopes[ownerGuid];

                    BehaviorVariableValue behaviourVariableValue = customScope.GetVariable(key);
                    if (behaviourVariableValue != null)
                    {
                        return(behaviourVariableValue);
                    }
                }
            }
            return(null);
        }
        public BehaviorVariableValue GetVariableWithMood(string key, AIMood mood)
        {
            if (this.ScopesByMood.ContainsKey(mood))
            {
                BehaviorVariableValue variable = this.ScopesByMood[mood].GetVariable(key);
                if (variable != null)
                {
                    return(variable);
                }
            }

            if (this.behaviorVariables.ContainsKey(key))
            {
                return(this.behaviorVariables[key]);
            }

            return(null);
        }
示例#8
0
        public static bool HasFollowLanceTarget(AbstractActor unit)
        {
            if (unit == null)
            {
                return(false);
            }

            BehaviorVariableValue value = AiManager.Instance.GetBehaviourVariableValue(unit, MoveToFollowLanceNode.FOLLOW_LANCE_TARGET_GUID_KEY);

            if (value != null)
            {
                string lanceGuid = value.StringVal;
                Lance  lance     = UnityGameInstance.BattleTechGame.Combat.ItemRegistry.GetItemByGUID(lanceGuid) as Lance;
                Main.Logger.Log($"[HasFollowLanceTarget] Unit '{unit.DisplayName}' has a follow target lance of guid '{lanceGuid}' and name '{lance.DisplayName}'");
                return(true);
            }

            return(false);
        }
    override protected BehaviorTreeResults Tick()
    {
        if (unit.lance == null)
        {
            Debug.Log("No lance for this unit found");
            return(new BehaviorTreeResults(BehaviorNodeState.Failure));
        }

        BehaviorVariableValue startedBV = unit.lance.BehaviorVariables.GetVariable(BehaviorVariableName.Bool_RouteStarted);

        if ((startedBV != null) && (startedBV.BoolVal))
        {
            return(new BehaviorTreeResults(BehaviorNodeState.Success));
        }
        else
        {
            return(new BehaviorTreeResults(BehaviorNodeState.Failure));
        }
    }
示例#10
0
 public static void Postfix(BehaviorTree __instance, ref BehaviorVariableValue __result, BehaviorVariableName name)
 {
     try
     {
         if (name == BehaviorVariableName.Bool_ReserveEnabled)
         {
             Logger.Debug("[BehaviorTree_GetBehaviorVariableValue_POSTFIX] Overriding BehaviorVariableName.Bool_ReserveEnabled: true");
             __result.BoolVal = true;
         }
         else if (name == BehaviorVariableName.Float_ReserveBasePercentage)
         {
             Logger.Debug("[BehaviorTree_GetBehaviorVariableValue_POSTFIX] Overriding BehaviorVariableName.Float_ReserveBasePercentage: " + LittleThings.Settings.EnableAIReserveBasePercentage);
             __result.FloatVal = LittleThings.Settings.EnableAIReserveBasePercentage;
         }
     }
     catch (Exception e)
     {
         Logger.Error(e);
     }
 }
    override protected BehaviorTreeResults Tick()
    {
        BehaviorVariableValue variableValue = tree.GetBehaviorVariableValue(BehaviorVariableName.String_LancePostAttackDestinationGUID);

        if (variableValue == null)
        {
            return(new BehaviorTreeResults(BehaviorNodeState.Failure));
        }

        string destinationGUID = variableValue.StringVal;

        RoutePointGameLogic destination = DestinationUtil.FindDestinationByGUID(tree, destinationGUID);

        if (destination == null)
        {
            return(new BehaviorTreeResults(BehaviorNodeState.Failure));
        }

        return(new BehaviorTreeResults(BehaviorNodeState.Success));
    }
    override protected BehaviorTreeResults Tick()
    {
        BehaviorVariableValue variableValue = tree.GetBehaviorVariableValue(BehaviorVariableName.String_RouteGUID);

        if (variableValue == null)
        {
            // No route, this is normal.
            return(new BehaviorTreeResults(BehaviorNodeState.Failure));
        }

        string patrolRouteGUID = variableValue.StringVal;

        RouteGameLogic route = RoutingUtil.FindRouteByGUID(tree, patrolRouteGUID);

        if (route == null)
        {
            return(new BehaviorTreeResults(BehaviorNodeState.Failure));
        }

        return(new BehaviorTreeResults(BehaviorNodeState.Success));
    }
        // TODO: Need to cover vanilla deserialisation for `CustomBehaviorVariableScope` type before this will work
        // TODO: Patch a call into this for the unit to save the data into the save file, or output as a companion save file
        public void Hydrate(SerializableReferenceContainer references)
        {
            Dictionary <string, BehaviorVariableValue>    itemDictionary  = references.GetItemDictionary <string, BehaviorVariableValue>(this, "serializableCustomBehaviorVariables");
            Dictionary <int, CustomBehaviorVariableScope> itemDictionary2 = references.GetItemDictionary <int, CustomBehaviorVariableScope>(this, "serializableCustomScopesByMood");

            this.behaviorVariables = new Dictionary <string, BehaviorVariableValue>(itemDictionary.Count);

            foreach (KeyValuePair <string, BehaviorVariableValue> keyValuePair in itemDictionary)
            {
                string key = (string)keyValuePair.Key;
                BehaviorVariableValue value = keyValuePair.Value;
                this.behaviorVariables.Add(key, value);
            }

            this.ScopesByMood = new Dictionary <AIMood, CustomBehaviorVariableScope>(itemDictionary2.Count);
            foreach (KeyValuePair <int, CustomBehaviorVariableScope> keyValuePair2 in itemDictionary2)
            {
                AIMood key2 = (AIMood)keyValuePair2.Key;
                CustomBehaviorVariableScope value2 = keyValuePair2.Value;
                this.ScopesByMood.Add(key2, value2);
            }
        }
        // TODO: Need to cover vanilla serialisation for `CustomBehaviorVariableScope` type before this will work
        // TODO: Patch a call into this for the unit to load the data from the save file, or output as a companion save file
        public void Dehydrate(SerializableReferenceContainer references)
        {
            Dictionary <string, BehaviorVariableValue>    dictionary  = new Dictionary <string, BehaviorVariableValue>(this.behaviorVariables.Count);
            Dictionary <int, CustomBehaviorVariableScope> dictionary2 = new Dictionary <int, CustomBehaviorVariableScope>(this.ScopesByMood.Count);

            foreach (KeyValuePair <string, BehaviorVariableValue> keyValuePair in this.behaviorVariables)
            {
                string key = (string)keyValuePair.Key;
                BehaviorVariableValue value = keyValuePair.Value;
                dictionary.Add(key, value);
            }

            foreach (KeyValuePair <AIMood, CustomBehaviorVariableScope> keyValuePair2 in this.ScopesByMood)
            {
                int key2 = (int)keyValuePair2.Key;
                CustomBehaviorVariableScope value2 = keyValuePair2.Value;
                dictionary2.Add(key2, value2);
            }

            references.AddItemDictionary <string, BehaviorVariableValue>(this, "serializableCustomBehaviorVariables", dictionary);
            references.AddItemDictionary <int, CustomBehaviorVariableScope>(this, "serializableCustomScopesByMood", dictionary2);
        }
示例#15
0
        public BehaviorVariableValue GetBehaviourVariableValue(AbstractActor unit, string key)
        {
            BehaviorVariableValue behaviourVariableValue = GetBehaviourVariableValue("UNIT", unit.GUID, key);

            if (behaviourVariableValue != null)
            {
                return(behaviourVariableValue);
            }

            behaviourVariableValue = GetBehaviourVariableValue("LANCE", unit.lance.GUID, key);
            if (behaviourVariableValue != null)
            {
                return(behaviourVariableValue);
            }

            behaviourVariableValue = GetBehaviourVariableValue("TEAM", unit.team.GUID, key);
            if (behaviourVariableValue != null)
            {
                return(behaviourVariableValue);
            }

            return(null);
        }
        static string bvToString(BehaviorVariableName name, BehaviorVariableValue bvv)
        {
            string nameString = name.ToString();

            switch (bvv.type)
            {
            case BehaviorVariableValue.BehaviorVariableType.Bool:
                return(string.Format("{0}: {1}", nameString, bvv.BoolVal));

            case BehaviorVariableValue.BehaviorVariableType.String:
                return(string.Format("{0}: {1}", nameString, bvv.StringVal));

            case BehaviorVariableValue.BehaviorVariableType.Int:
                return(string.Format("{0}: {1}", nameString, bvv.IntVal));

            case BehaviorVariableValue.BehaviorVariableType.Float:
                return(string.Format("{0}: {1}", nameString, bvv.FloatVal));

            default:
                Debug.LogAssertion("unknown behavior variable type" + bvv.type);
                return("???");
            }
        }
        // TODO: EVERYTHING SHOULD CONVERT TO CACHED CALL IF POSSIBLE
        public static BehaviorVariableValue GetBehaviorVariableValue(BehaviorTree bTree, BehaviorVariableName name)
        {
            BehaviorVariableValue bhVarVal = null;

            if (ModState.RolePlayerBehaviorVarManager != null && ModState.RolePlayerGetBehaviorVar != null)
            {
                // Ask RolePlayer for the variable
                //getBehaviourVariable(AbstractActor actor, BehaviorVariableName name)
                Mod.Log.Trace?.Write($"Pulling BehaviorVariableValue from RolePlayer for unit: {bTree.unit.DistinctId()}.");
                bhVarVal = (BehaviorVariableValue)ModState.RolePlayerGetBehaviorVar.Invoke(ModState.RolePlayerBehaviorVarManager, new object[] { bTree.unit, name });
            }

            if (bhVarVal == null)
            {
                // RolePlayer does not return the vanilla value if there's no configuration for the actor. We need to check that we're null here to trap that edge case.
                // Also, if RolePlayer isn't configured we need to read the value.
                Mod.Log.Trace?.Write($"Pulling BehaviorVariableValue from Vanilla for unit: {bTree.unit.DistinctId()}.");
                bhVarVal = GetBehaviorVariableValueDirectly(bTree, name);
            }

            Mod.Log.Trace?.Write($"  Value is: {bhVarVal}");
            return(bhVarVal);
        }
    public static Vector3 Decrowd(Vector3 target, AbstractActor unit)
    {
        float myRadius           = unit.BehaviorTree.GetBehaviorVariableValue(BehaviorVariableName.Float_PersonalSpaceRadius).FloatVal;
        List <ITaggedItem> units = unit.BehaviorTree.battleTechGame.Combat.ItemRegistry.WithType(TaggedObjectType.Unit).Search();

        float testOffsetRadius = 0.0f;
        float testOffsetAngle  = 0.0f;

        while (testOffsetRadius < 10.0f * myRadius)
        {
            Vector3 candidatePoint = new Vector3(target.x + Mathf.Cos(testOffsetAngle) * testOffsetRadius,
                                                 target.y,
                                                 target.z + Mathf.Sin(testOffsetAngle) * testOffsetRadius);

            bool anyViolatedConstraints = false;

            for (int unitIndex = 0; unitIndex < units.Count; ++unitIndex)
            {
                AbstractActor otherUnit = units[unitIndex] as AbstractActor;
                if (otherUnit == unit)
                {
                    continue;
                }

                float otherRadius = 0.0f;
                if (otherUnit.BehaviorTree != null)
                {
                    BehaviorVariableValue otherRadiusValue = otherUnit.BehaviorTree.GetBehaviorVariableValue(BehaviorVariableName.Float_PersonalSpaceRadius);
                    if (otherRadiusValue != null)
                    {
                        otherRadius = otherRadiusValue.FloatVal;
                    }
                }
                float desiredRadius = myRadius + otherRadius;

                Vector3 constraintVector    = candidatePoint - otherUnit.CurrentPosition;
                float   constraintVectorMag = constraintVector.magnitude;
                if (constraintVectorMag < desiredRadius)
                {
                    anyViolatedConstraints = true;
                    break;
                }
            }
            if (!anyViolatedConstraints)
            {
                return(candidatePoint);
            }

            float newWrap = testOffsetAngle * testOffsetRadius + myRadius;
            if (newWrap > Mathf.PI * 2 * testOffsetRadius)
            {
                testOffsetRadius += myRadius;
            }

            if (testOffsetRadius > 0.0f)
            {
                testOffsetAngle = newWrap / testOffsetRadius;
                testOffsetAngle = testOffsetAngle % (Mathf.PI * 2);
            }
        }

        // TODO: do something fancier here.
        return(target);
    }
示例#19
0
        protected override BehaviorTreeResults Tick()
        {
            if (unit.HasMovedThisRound)
            {
                return(new BehaviorTreeResults(BehaviorNodeState.Failure));
            }

            BehaviorVariableValue targetLanceGuidValue = this.tree.GetCustomBehaviorVariableValue(FOLLOW_LANCE_TARGET_GUID_KEY);

            if (targetLanceGuidValue == null)
            {
                return(new BehaviorTreeResults(BehaviorNodeState.Failure));
            }

            string targetLanceGuid = targetLanceGuidValue.StringVal;
            Lance  targetLance     = DestinationUtil.FindLanceByGUID(this.tree, targetLanceGuid);

            if (targetLance == null)
            {
                return(new BehaviorTreeResults(BehaviorNodeState.Failure));
            }
            List <AbstractActor> lanceMembers = AIUtil.GetLanceUnits(this.unit.Combat, this.unit.LanceId);

            float travelDistance = Mathf.Max(this.unit.MaxSprintDistance, this.unit.MaxWalkDistance);

            if (this.waitForLance)
            {
                for (int i = 0; i < lanceMembers.Count; i++)
                {
                    AbstractActor abstractActor = lanceMembers[i] as AbstractActor;

                    if (abstractActor != null)
                    {
                        float lanceMemberTravelDistance = Mathf.Max(abstractActor.MaxWalkDistance, abstractActor.MaxSprintDistance);
                        travelDistance = Mathf.Min(travelDistance, lanceMemberTravelDistance);
                    }
                }
            }

            AbstractActor targetActor   = null;
            float         targetTonnage = 0;

            for (int i = 0; i < targetLance.unitGuids.Count; i++)
            {
                ITaggedItem itemByGUID = this.unit.Combat.ItemRegistry.GetItemByGUID(targetLance.unitGuids[i]);

                if (itemByGUID != null)
                {
                    AbstractActor abstractActor = itemByGUID as AbstractActor;

                    if (abstractActor != null && !abstractActor.IsDead)
                    {
                        if (abstractActor is Mech)
                        {
                            Mech mech = (Mech)abstractActor;
                            if (mech.tonnage > targetTonnage)
                            {
                                targetActor   = mech;
                                targetTonnage = mech.tonnage;
                            }
                        }
                        else if (abstractActor is Vehicle)
                        {
                            Vehicle vehicle = (Vehicle)abstractActor;
                            if (vehicle.tonnage > targetTonnage)
                            {
                                targetActor   = vehicle;
                                targetTonnage = vehicle.tonnage;
                            }
                        }
                    }
                }
            }

            if (targetActor == null)
            {
                Main.Logger.LogError("[MoveToFollowLanceNode] Target Actor is null");
                return(new BehaviorTreeResults(BehaviorNodeState.Failure));
            }

            Main.LogDebug($"[MoveToFollowLanceNode] Target to follow is '{targetActor.DisplayName} {targetActor.VariantName}'");

            bool shouldSprint = this.tree.GetCustomBehaviorVariableValue(FOLLOW_LANCE_SHOULD_SPRINT_KEY).BoolVal;

            shouldSprint = (!this.unit.HasAnyContactWithEnemy);
            shouldSprint = (this.unit.CurrentPosition - targetActor.CurrentPosition).magnitude > 200f; // sprint if the unit is over 200 metres away

            AbstractActor closestDetectedEnemy = AiUtils.GetClosestDetectedEnemy(this.unit, targetLance);
            Vector3       lookDirection        = (closestDetectedEnemy == null) ? targetActor.CurrentPosition : closestDetectedEnemy.CurrentPosition;

            MoveType moveType = (shouldSprint) ? MoveType.Sprinting : MoveType.Walking;

            this.unit.Pathing.UpdateAIPath(targetActor.CurrentPosition, lookDirection, moveType);

            Vector3 vectorToTarget   = this.unit.Pathing.ResultDestination - this.unit.CurrentPosition;
            float   distanceToTarget = vectorToTarget.magnitude;

            if (distanceToTarget > travelDistance)
            {
                // If the target is out of range, head in the direction of that unit to the maximum possible travel distance for this turn
                vectorToTarget = vectorToTarget.normalized * travelDistance;
            }

            // Ensure the units aren't crowded
            Vector3 targetDestination = RoutingUtil.Decrowd(this.unit.CurrentPosition + vectorToTarget, this.unit);

            targetDestination = RegionUtil.MaybeClipMovementDestinationToStayInsideRegion(this.unit, targetDestination);

            float followLanceZoneRadius = this.unit.BehaviorTree.GetCustomBehaviorVariableValue(FOLLOW_LANCE_ZONE_RADIUS_KEY).FloatVal;

            if (RoutingUtils.IsUnitInsideRadiusOfPoint(this.unit, targetActor.CurrentPosition, followLanceZoneRadius))
            {
                return(new BehaviorTreeResults(BehaviorNodeState.Failure));
            }

            this.unit.Pathing.UpdateAIPath(targetDestination, lookDirection, (shouldSprint) ? MoveType.Sprinting : MoveType.Walking);
            targetDestination = this.unit.Pathing.ResultDestination;
            float        maxCost             = this.unit.Pathing.MaxCost;
            PathNodeGrid currentGrid         = this.unit.Pathing.CurrentGrid;
            Vector3      targetActorPosition = targetActor.CurrentPosition;

            if ((currentGrid.GetValidPathNodeAt(targetDestination, maxCost) == null || (targetDestination - targetActor.CurrentPosition).magnitude > 1f) && this.unit.Combat.EncounterLayerData.inclineMeshData != null)
            {
                float maxSlope = Mathf.Tan(0.0174532924f * AIUtil.GetMaxSteepnessForAllLance(this.unit));
                List <AbstractActor> lanceUnits = AIUtil.GetLanceUnits(this.unit.Combat, this.unit.LanceId);
                targetDestination = this.unit.Combat.EncounterLayerData.inclineMeshData.GetDestination(this.unit.CurrentPosition, targetDestination, maxCost, maxSlope, this.unit, shouldSprint, lanceUnits, this.unit.Pathing.CurrentGrid, out targetActorPosition);
            }

            Vector3 currentPosition = this.unit.CurrentPosition;

            AIUtil.LogAI(string.Format("issuing order from [{0} {1} {2}] to [{3} {4} {5}] looking at [{6} {7} {8}]", new object[] {
                currentPosition.x,
                currentPosition.y,
                currentPosition.z,
                targetDestination.x,
                targetDestination.y,
                targetDestination.z,
                targetActorPosition.x,
                targetActorPosition.y,
                targetActorPosition.z
            }), "AI.DecisionMaking");

            return(new BehaviorTreeResults(BehaviorNodeState.Success)
            {
                orderInfo = new MovementOrderInfo(targetDestination, targetActorPosition)
                {
                    IsSprinting = shouldSprint
                },
                debugOrderString = string.Format("{0} moving toward destination: {1} dest: {2}", this.name, targetDestination, targetActor.CurrentPosition)
            });
        }
    override protected BehaviorTreeResults Tick()
    {
        BehaviorTreeResults results;

        if (unit.BehaviorTree.GetBehaviorVariableValue(BehaviorVariableName.Bool_RouteCompleted).BoolVal)
        {
            results                  = new BehaviorTreeResults(BehaviorNodeState.Success);
            results.orderInfo        = new OrderInfo(OrderType.Brace);
            results.debugOrderString = string.Format("{0}: bracing for end of patrol route", this.name);
            return(results);
        }

        bool isSprinting = unit.BehaviorTree.GetBehaviorVariableValue(BehaviorVariableName.Bool_RouteShouldSprint).BoolVal;

        if (isSprinting && unit.CanSprint)
        {
            unit.Pathing.SetSprinting();
        }
        else
        {
            unit.Pathing.SetWalking();
        }

        PathNodeGrid grid = unit.Pathing.CurrentGrid;

        if (grid.UpdateBuild(25) > 0)
        {
            // have to wait for the grid to build.
            results = new BehaviorTreeResults(BehaviorNodeState.Running);
            return(results);
        }

        if (!unit.Pathing.ArePathGridsComplete)
        {
            // have to wait for the grid to build.
            results = new BehaviorTreeResults(BehaviorNodeState.Running);
            return(results);
        }

        float destinationRadius = unit.BehaviorTree.GetBehaviorVariableValue(BehaviorVariableName.Float_RouteWaypointRadius).FloatVal;

        RouteGameLogic myPatrolRoute = getRoute();

        if (myPatrolRoute == null)
        {
            AIUtil.LogAI("Move Along Route failing because no route found", unit);
            return(new BehaviorTreeResults(BehaviorNodeState.Failure));
        }

        BehaviorVariableValue nrpiVal = unit.BehaviorTree.GetBehaviorVariableValue(BehaviorVariableName.Int_RouteTargetPoint);
        int nextRoutePointIndex       = (nrpiVal != null) ? nrpiVal.IntVal : 0;
        BehaviorVariableValue pfVal   = unit.BehaviorTree.GetBehaviorVariableValue(BehaviorVariableName.Bool_RouteFollowingForward);
        bool patrollingForward        = (pfVal != null) ? pfVal.BoolVal : true;

        PatrolRouteWaypoints routeWaypointIterator = null;

        switch (myPatrolRoute.routeTransitType)
        {
        case RouteTransitType.Circuit:
            routeWaypointIterator = new CircuitRouteWaypoints(nextRoutePointIndex, patrollingForward, myPatrolRoute.routePointList.Length);
            break;

        case RouteTransitType.OneWay:
            routeWaypointIterator = new OneWayRouteWaypoints(nextRoutePointIndex, patrollingForward, myPatrolRoute.routePointList.Length);
            break;

        case RouteTransitType.PingPong:
            routeWaypointIterator = new PingPongRouteWaypoints(nextRoutePointIndex, patrollingForward, myPatrolRoute.routePointList.Length);
            break;

        default:
            Debug.LogError("Invalid route transit type: " + myPatrolRoute.routeTransitType);
            AIUtil.LogAI("Move Along Route failing because patrol route was set to an invalid transit type: " + myPatrolRoute.routeTransitType, unit);
            return(new BehaviorTreeResults(BehaviorNodeState.Failure));
        }

        float movementAvailable = unit.Pathing.MaxCost * unit.BehaviorTree.GetBehaviorVariableValue(BehaviorVariableName.Float_PatrolRouteThrottlePercentage).FloatVal / 100.0f;

        bool            isComplete           = false;
        int             nextWaypoint         = -1;
        bool            nextPointGoesForward = false;
        Vector3         successorPoint;
        List <PathNode> availablePathNodes = unit.Pathing.CurrentGrid.GetSampledPathNodes();

        // prune for region
        string regionGUID = RegionUtil.StayInsideRegionGUID(unit);

        if (!string.IsNullOrEmpty(regionGUID))
        {
            availablePathNodes = availablePathNodes.FindAll(node => RegionUtil.PointInRegion(unit.Combat, node.Position, regionGUID));
        }

        string guardGUID  = unit.BehaviorTree.GetBehaviorVariableValue(BehaviorVariableName.String_GuardLanceGUID).StringVal;
        Lance  guardLance = guardGUID != null?unit.Combat.ItemRegistry.GetItemByGUID <Lance>(guardGUID) : null;

        // if guarding units, adjust movement available to account for their speed
        if (guardLance != null)
        {
            movementAvailable = adjustMovementAvailableForGuardLance(unit, movementAvailable, guardLance);
        }

        // prune for distance from start point
        availablePathNodes = availablePathNodes.FindAll(node => node.CostToThisNode <= movementAvailable);

        // if there is a guarding lance, make sure that we're not moving out of the lance tether
        if (guardLance != null)
        {
            availablePathNodes = filterAvailablePathNodesForGuardTether(unit, availablePathNodes, guardLance);
        }


        Vector3 patrolPoint = getReachablePointOnRoute(unit.CurrentPosition, myPatrolRoute, routeWaypointIterator, availablePathNodes, out isComplete, out nextWaypoint, out nextPointGoesForward, out successorPoint);

        unit.BehaviorTree.unitBehaviorVariables.SetVariable(BehaviorVariableName.Bool_RouteFollowingForward, new BehaviorVariableValue(nextPointGoesForward));
        unit.BehaviorTree.unitBehaviorVariables.SetVariable(BehaviorVariableName.Int_RouteTargetPoint, new BehaviorVariableValue(nextWaypoint));
        unit.BehaviorTree.unitBehaviorVariables.SetVariable(BehaviorVariableName.Bool_RouteCompleted, new BehaviorVariableValue(isComplete));

        //Vector3 destination = RegionUtil.MaybeClipMovementDestinationToStayInsideRegion(unit, patrolPoint);
        Vector3 destination = patrolPoint;

        if (!isComplete)
        {
            List <PathNode> path = constructPath(unit.Combat.HexGrid, destination, availablePathNodes);

            if ((path.Count == 0) || ((path.Count == 1) && (AIUtil.Get2DDistanceBetweenVector3s(path[0].Position, unit.CurrentPosition) < 1)))
            {
                // can't actually make progress - fail here, and presumably pass later on.
                AIUtil.LogAI("Move Along Route failing because no nodes in path.", unit);

                DialogueGameLogic proximityDialogue = unit.Combat.ItemRegistry.GetItemByGUID <DialogueGameLogic>(unit.Combat.Constants.CaptureEscortProximityDialogID);

                if (proximityDialogue != null)
                {
                    TriggerDialog triggerDialogueMessage = new TriggerDialog(unit.GUID, unit.Combat.Constants.CaptureEscortProximityDialogID, async: false);
                    unit.Combat.MessageCenter.PublishMessage(triggerDialogueMessage);
                }
                else
                {
                    Debug.LogError("Could not find CaptureEscortProximityDialog. This is only a real error message if this is a Capture Escort (Normal Escort) mission. For other missions (Story, Ambush Convoy, etc) you can safely ignore this error message.");
                }

                return(new BehaviorTreeResults(BehaviorNodeState.Failure));
            }

            destination = path[path.Count - 1].Position;
        }

        Vector3 cur = unit.CurrentPosition;

        if ((destination - cur).magnitude < 1)
        {
            // can't actually make progress - fail here, and presumably pass later on.
            AIUtil.LogAI("Move Along Route failing because destination too close to unit start.", unit);
            return(new BehaviorTreeResults(BehaviorNodeState.Failure));
        }

        AIUtil.LogAI(string.Format("issuing order from [{0} {1} {2}] to [{3} {4} {5}] looking at [{6} {7} {8}]",
                                   cur.x, cur.y, cur.z,
                                   destination.x, destination.y, destination.z,
                                   successorPoint.x, successorPoint.y, successorPoint.z
                                   ), unit);

        results = new BehaviorTreeResults(BehaviorNodeState.Success);
        MovementOrderInfo mvtOrderInfo = new MovementOrderInfo(destination, successorPoint);

        mvtOrderInfo.IsSprinting = isSprinting;
        results.orderInfo        = mvtOrderInfo;
        results.debugOrderString = string.Format("{0}: dest:{1} sprint:{2}", this.name, destination, mvtOrderInfo.IsSprinting);
        return(results);
    }
 public void SetVariable(string key, BehaviorVariableValue value)
 {
     this.behaviorVariables[key] = value;
 }
    override protected BehaviorTreeResults Tick()
    {
        BehaviorVariableValue variableValue = tree.GetBehaviorVariableValue(destinationBVarName);

        if (variableValue == null)
        {
            return(new BehaviorTreeResults(BehaviorNodeState.Failure));
        }

        string destinationGUID = variableValue.StringVal;

        RoutePointGameLogic destination = DestinationUtil.FindDestinationByGUID(tree, destinationGUID);

        if (destination == null)
        {
            return(new BehaviorTreeResults(BehaviorNodeState.Failure));
        }

        float sprintDistance = Mathf.Max(unit.MaxSprintDistance, unit.MaxWalkDistance);

        if (waitForLance)
        {
            for (int lanceMemberIndex = 0; lanceMemberIndex < unit.lance.unitGuids.Count; ++lanceMemberIndex)
            {
                ITaggedItem item = unit.Combat.ItemRegistry.GetItemByGUID(unit.lance.unitGuids[lanceMemberIndex]);
                if (item == null)
                {
                    continue;
                }
                AbstractActor lanceUnit = item as AbstractActor;
                if (lanceUnit == null)
                {
                    continue;
                }
                float unitMoveDistance = Mathf.Max(lanceUnit.MaxWalkDistance, lanceUnit.MaxSprintDistance);
                sprintDistance = Mathf.Min(sprintDistance, unitMoveDistance);
            }
        }

        MoveType moveType = tree.GetBehaviorVariableValue(BehaviorVariableName.Bool_RouteShouldSprint).BoolVal ?
                            MoveType.Sprinting : MoveType.Walking;

        unit.Pathing.UpdateAIPath(destination.Position, destination.Position, moveType);

        Vector3 offset = unit.Pathing.ResultDestination - unit.CurrentPosition;

        if (offset.magnitude > sprintDistance)
        {
            offset = offset.normalized * sprintDistance;
        }

        Vector3 destinationThisTurn = RoutingUtil.Decrowd(unit.CurrentPosition + offset, unit);

        destinationThisTurn = RegionUtil.MaybeClipMovementDestinationToStayInsideRegion(unit, destinationThisTurn);

        float destinationRadius = unit.BehaviorTree.GetBehaviorVariableValue(BehaviorVariableName.Float_RouteWaypointRadius).FloatVal;

        List <AbstractActor> unitsToWaitFor = new List <AbstractActor>();

        if (waitForLance)
        {
            if (unit.lance != null)
            {
                for (int lanceGUIDIndex = 0; lanceGUIDIndex < unit.lance.unitGuids.Count; ++lanceGUIDIndex)
                {
                    string      guid = unit.lance.unitGuids[lanceGUIDIndex];
                    ITaggedItem item = unit.Combat.ItemRegistry.GetItemByGUID(guid);
                    if (item != null)
                    {
                        AbstractActor lanceUnit = item as AbstractActor;
                        if (lanceUnit != null)
                        {
                            unitsToWaitFor.Add(lanceUnit);
                        }
                    }
                }
            }
            else
            {
                unitsToWaitFor.Add(unit);
            }
        }
        if (RoutingUtil.AllUnitsInsideRadiusOfPoint(unitsToWaitFor, destination.Position, destinationRadius))
        {
            tree.RemoveBehaviorVariableValue(destinationBVarName);
        }

        bool isSprinting = tree.GetBehaviorVariableValue(BehaviorVariableName.Bool_RouteShouldSprint).BoolVal;

        unit.Pathing.UpdateAIPath(destinationThisTurn, destination.Position, isSprinting ? MoveType.Sprinting : MoveType.Walking);
        destinationThisTurn = unit.Pathing.ResultDestination;

        float        movementBudget = unit.Pathing.MaxCost;
        PathNodeGrid grid           = unit.Pathing.CurrentGrid;
        Vector3      successorPoint = destination.Position;

        if ((grid.GetValidPathNodeAt(destinationThisTurn, movementBudget) == null) ||
            ((destinationThisTurn - destination.Position).magnitude > 1.0f))
        {
            // can't get all the way to the destination.
            if (unit.Combat.EncounterLayerData.inclineMeshData != null)
            {
                float maxSteepnessRatio         = Mathf.Tan(Mathf.Deg2Rad * AIUtil.GetMaxSteepnessForAllLance(unit));
                List <AbstractActor> lanceUnits = AIUtil.GetLanceUnits(unit.Combat, unit.LanceId);
                destinationThisTurn = unit.Combat.EncounterLayerData.inclineMeshData.GetDestination(
                    unit.CurrentPosition,
                    destinationThisTurn,
                    movementBudget,
                    maxSteepnessRatio,
                    unit,
                    isSprinting,
                    lanceUnits,
                    unit.Pathing.CurrentGrid,
                    out successorPoint);
            }
        }

        Vector3 cur = unit.CurrentPosition;

        AIUtil.LogAI(string.Format("issuing order from [{0} {1} {2}] to [{3} {4} {5}] looking at [{6} {7} {8}]",
                                   cur.x, cur.y, cur.z,
                                   destinationThisTurn.x, destinationThisTurn.y, destinationThisTurn.z,
                                   successorPoint.x, successorPoint.y, successorPoint.z
                                   ));

        BehaviorTreeResults results      = new BehaviorTreeResults(BehaviorNodeState.Success);
        MovementOrderInfo   mvtOrderInfo = new MovementOrderInfo(destinationThisTurn, successorPoint);

        mvtOrderInfo.IsSprinting = isSprinting;
        results.orderInfo        = mvtOrderInfo;
        results.debugOrderString = string.Format("{0} moving toward destination: {1} dest: {2}", this.name, destinationThisTurn, destination.Position);
        return(results);
    }
示例#23
0
        protected override BehaviorTreeResults Tick()
        {
            if (unit.HasMovedThisRound)
            {
                return(new BehaviorTreeResults(BehaviorNodeState.Failure));
            }

            BehaviorVariableValue targetLanceGuidValue = this.tree.GetCustomBehaviorVariableValue(FOLLOW_LANCE_TARGET_GUID_KEY);

            if (targetLanceGuidValue == null)
            {
                return(new BehaviorTreeResults(BehaviorNodeState.Failure));
            }

            string targetLanceGuid = targetLanceGuidValue.StringVal;
            Lance  targetLance     = DestinationUtil.FindLanceByGUID(this.tree, targetLanceGuid);

            if (targetLance == null)
            {
                return(new BehaviorTreeResults(BehaviorNodeState.Failure));
            }

            AbstractActor closestEnemy = null;

            if (Main.Settings.AiSettings.FollowAiSettings.StopWhen == "OnEnemyVisible")
            {
                Main.LogDebug($"[MoveToFollowLanceNode] Looking for closest visible enemy.");
                closestEnemy = AiUtils.GetClosestVisibleEnemy(this.unit, targetLance);
            }
            else // OnEnemyDetected
            {
                Main.LogDebug($"[MoveToFollowLanceNode] Looking for closest detected enemy.");
                closestEnemy = AiUtils.GetClosestDetectedEnemy(this.unit, targetLance);
            }

            if (closestEnemy != null)
            {
                if (Main.Settings.AiSettings.FollowAiSettings.StopWhen != "WhenNotNeeded")
                {
                    Main.LogDebug($"[MoveToFollowLanceNode] Detected enemy. No longer following player mech.");
                    return(new BehaviorTreeResults(BehaviorNodeState.Failure));
                }
                else
                {
                    Main.LogDebug($"[MoveToFollowLanceNode] Enemies detected but keeping tight formation still. Following player mech.");
                }
            }
            else
            {
                Main.LogDebug($"[MoveToFollowLanceNode] No enemies detected. Following player mech.");
            }


            List <AbstractActor> lanceMembers = AIUtil.GetLanceUnits(this.unit.Combat, this.unit.LanceId);
            float travelDistance = Mathf.Max(this.unit.MaxSprintDistance, this.unit.MaxWalkDistance);

            if (this.waitForLance)
            {
                for (int i = 0; i < lanceMembers.Count; i++)
                {
                    AbstractActor abstractActor = lanceMembers[i] as AbstractActor;

                    if (abstractActor != null)
                    {
                        float lanceMemberTravelDistance = Mathf.Max(abstractActor.MaxWalkDistance, abstractActor.MaxSprintDistance);
                        travelDistance = Mathf.Min(travelDistance, lanceMemberTravelDistance);
                    }
                }
            }

            AbstractActor targetActor = GetMechToFollow(targetLance);

            if (targetActor == null)
            {
                Main.Logger.LogError("[MoveToFollowLanceNode] Target Actor is null");
                return(new BehaviorTreeResults(BehaviorNodeState.Failure));
            }

            Main.LogDebug($"[MoveToFollowLanceNode] Target to follow is '{targetActor.DisplayName} {targetActor.VariantName}'");

            bool shouldSprint = this.tree.GetCustomBehaviorVariableValue(FOLLOW_LANCE_SHOULD_SPRINT_KEY).BoolVal;

            Main.LogDebug($"[MoveToFollowLanceNode] Should sprint by behaviour value being set? '{shouldSprint}'");

            shouldSprint = (!this.unit.HasAnyContactWithEnemy);

            Main.LogDebug($"[MoveToFollowLanceNode] Should sprint by contact with enemy? '{shouldSprint}'");

            shouldSprint = (this.unit.CurrentPosition - targetActor.CurrentPosition).magnitude > Main.Settings.AiSettings.FollowAiSettings.MaxDistanceFromTargetBeforeSprinting; // sprint if the unit is over 200 metres away
            Main.LogDebug($"[MoveToFollowLanceNode] Is the follow target further than 200m? Should sprint? '{shouldSprint}'");

            Vector3  lookDirection = (closestEnemy == null) ? targetActor.CurrentPosition : closestEnemy.CurrentPosition;
            MoveType moveType      = (shouldSprint) ? MoveType.Sprinting : MoveType.Walking;

            this.unit.Pathing.UpdateAIPath(targetActor.CurrentPosition, lookDirection, moveType);

            Vector3 vectorToTarget   = this.unit.Pathing.ResultDestination - this.unit.CurrentPosition;
            float   distanceToTarget = vectorToTarget.magnitude;

            if (distanceToTarget > travelDistance)
            {
                Main.LogDebug($"[MoveToFollowLanceNode] Can't reach follow target in one go so will go as far as I can");
                // If the target is out of range, head in the direction of that unit to the maximum possible travel distance for this turn
                vectorToTarget = vectorToTarget.normalized * travelDistance;
            }

            // Ensure the units aren't crowded
            Vector3 targetDestination = RoutingUtil.Decrowd(this.unit.CurrentPosition + vectorToTarget, this.unit);

            targetDestination = RegionUtil.MaybeClipMovementDestinationToStayInsideRegion(this.unit, targetDestination);

            float followLanceZoneRadius = this.unit.BehaviorTree.GetCustomBehaviorVariableValue(FOLLOW_LANCE_ZONE_RADIUS_KEY).FloatVal;

            Main.LogDebug($"[MoveToFollowLanceNode] My follow zone radius is '{followLanceZoneRadius}'");
            if (RoutingUtils.IsUnitInsideRadiusOfPoint(this.unit, targetActor.CurrentPosition, followLanceZoneRadius))
            {
                Main.LogDebug($"[MoveToFollowLanceNode] ...and I am inside that zone.");
                return(new BehaviorTreeResults(BehaviorNodeState.Failure));
            }
            else
            {
                Main.LogDebug($"[MoveToFollowLanceNode] ...and I am NOT inside that zone.");
            }

            this.unit.Pathing.UpdateAIPath(targetDestination, lookDirection, moveType);
            targetDestination = this.unit.Pathing.ResultDestination;
            float        maxCost             = this.unit.Pathing.MaxCost;
            PathNodeGrid currentGrid         = this.unit.Pathing.CurrentGrid;
            Vector3      targetActorPosition = targetActor.CurrentPosition;

            // This method seems to get called all the time - this is meant to be a last resort method I think. I wonder why the other AI pathfinding methods don't work?
            if ((currentGrid.GetValidPathNodeAt(targetDestination, maxCost) == null || (targetDestination - targetActor.CurrentPosition).magnitude > 1f) && this.unit.Combat.EncounterLayerData.inclineMeshData != null)
            {
                float maxSlope = Mathf.Tan(0.0174532924f * AIUtil.GetMaxSteepnessForAllLance(this.unit));
                List <AbstractActor> lanceUnits = AIUtil.GetLanceUnits(this.unit.Combat, this.unit.LanceId);
                targetDestination = this.unit.Combat.EncounterLayerData.inclineMeshData.GetDestination(this.unit.CurrentPosition, targetDestination, maxCost, maxSlope, this.unit, shouldSprint, lanceUnits, this.unit.Pathing.CurrentGrid, out targetActorPosition);
            }

            Vector3 currentPosition = this.unit.CurrentPosition;

            AIUtil.LogAI(string.Format("issuing order from [{0} {1} {2}] to [{3} {4} {5}] looking at [{6} {7} {8}]", new object[] {
                currentPosition.x,
                currentPosition.y,
                currentPosition.z,
                targetDestination.x,
                targetDestination.y,
                targetDestination.z,
                targetActorPosition.x,
                targetActorPosition.y,
                targetActorPosition.z
            }), "AI.DecisionMaking");

            // TODO: Factor in jump mechs
            return(new BehaviorTreeResults(BehaviorNodeState.Success)
            {
                orderInfo = new MovementOrderInfo(targetDestination, targetActorPosition)
                {
                    IsSprinting = shouldSprint
                },
                debugOrderString = string.Format("{0} moving toward destination: {1} dest: {2}", this.name, targetDestination, targetActor.CurrentPosition)
            });
        }
        private static BehaviorVariableValue GetBehaviorVariableValueDirectly(BehaviorTree bTree, BehaviorVariableName name)
        {
            BehaviorVariableValue behaviorVariableValue = bTree.unitBehaviorVariables.GetVariable(name);

            if (behaviorVariableValue != null)
            {
                return(behaviorVariableValue);
            }

            Pilot pilot = bTree.unit.GetPilot();

            if (pilot != null)
            {
                BehaviorVariableScope scopeForAIPersonality = bTree.unit.Combat.BattleTechGame.BehaviorVariableScopeManager.GetScopeForAIPersonality(pilot.pilotDef.AIPersonality);
                if (scopeForAIPersonality != null)
                {
                    behaviorVariableValue = scopeForAIPersonality.GetVariableWithMood(name, bTree.unit.BehaviorTree.mood);
                    if (behaviorVariableValue != null)
                    {
                        return(behaviorVariableValue);
                    }
                }
            }

            if (bTree.unit.lance != null)
            {
                behaviorVariableValue = bTree.unit.lance.BehaviorVariables.GetVariable(name);
                if (behaviorVariableValue != null)
                {
                    return(behaviorVariableValue);
                }
            }

            if (bTree.unit.team != null)
            {
                Traverse bvT = Traverse.Create(bTree.unit.team).Field("BehaviorVariables");
                BehaviorVariableScope bvs = bvT.GetValue <BehaviorVariableScope>();
                behaviorVariableValue = bvs.GetVariable(name);
                if (behaviorVariableValue != null)
                {
                    return(behaviorVariableValue);
                }
            }

            UnitRole unitRole = bTree.unit.DynamicUnitRole;

            if (unitRole == UnitRole.Undefined)
            {
                unitRole = bTree.unit.StaticUnitRole;
            }

            BehaviorVariableScope scopeForRole = bTree.unit.Combat.BattleTechGame.BehaviorVariableScopeManager.GetScopeForRole(unitRole);

            if (scopeForRole != null)
            {
                behaviorVariableValue = scopeForRole.GetVariableWithMood(name, bTree.unit.BehaviorTree.mood);
                if (behaviorVariableValue != null)
                {
                    return(behaviorVariableValue);
                }
            }

            if (bTree.unit.CanMoveAfterShooting)
            {
                BehaviorVariableScope scopeForAISkill = bTree.unit.Combat.BattleTechGame.BehaviorVariableScopeManager.GetScopeForAISkill(AISkillID.Reckless);
                if (scopeForAISkill != null)
                {
                    behaviorVariableValue = scopeForAISkill.GetVariableWithMood(name, bTree.unit.BehaviorTree.mood);
                    if (behaviorVariableValue != null)
                    {
                        return(behaviorVariableValue);
                    }
                }
            }

            behaviorVariableValue = bTree.unit.Combat.BattleTechGame.BehaviorVariableScopeManager.GetGlobalScope().GetVariableWithMood(name, bTree.unit.BehaviorTree.mood);
            if (behaviorVariableValue != null)
            {
                return(behaviorVariableValue);
            }

            return(DefaultBehaviorVariableValue.GetSingleton());
        }
示例#25
0
        public static bool Prefix(BehaviorTree __instance, BehaviorVariableName name, ref BehaviorVariableValue __result)
        {
            var value = BehaviorVariableManager.Instance.getBehaviourVariable(__instance.unit, name);

            if (value == null)
            {
                return(true);
            }

            __result = value;
            return(false);
        }
示例#26
0
        public static bool Prefix(BehaviorTree __instance, BehaviorVariableName name, ref BehaviorVariableValue __result)
        {
            var value = BehaviorVariableOverride.TryOverrideValue(__instance, name);

            if (value == null)
            {
                return(true);
            }

            __result = value;
            return(false);
        }