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)); }
int closestPointOnRouteToLance(RouteGameLogic route, Lance lance) { Vector3 lanceCenter = Vector3.zero; int count = 0; for (int unitIndex = 0; unitIndex < lance.unitGuids.Count; ++unitIndex) { string unitGUID = lance.unitGuids[unitIndex]; ITaggedItem item = tree.battleTechGame.Combat.ItemRegistry.GetItemByGUID(unitGUID); if (item == null) { continue; } AbstractActor unit = item as AbstractActor; if (unit == null) { continue; } if (unit.IsDead) { continue; } ++count; lanceCenter += unit.CurrentPosition; } if (count == 0) { return(0); } lanceCenter *= 1.0f / count; float bestDist = float.MaxValue; int bestIndex = -1; // Now iterate over all points, to find closest point to this center point. for (int waypointIndex = 0; waypointIndex < route.routePointList.Length; ++waypointIndex) { RoutePointGameLogic point = route.routePointList[waypointIndex]; float dist = (point.Position - lanceCenter).magnitude; if (dist < bestDist) { bestIndex = waypointIndex; bestDist = dist; } } return(bestIndex); }
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)); }
Vector3 getReachablePointOnRoute(Vector3 startPosition, RouteGameLogic patrolRoute, PatrolRouteWaypoints waypointIterator, List <PathNode> validDestinations, out bool isComplete, out int nextWaypointIndex, out bool nextPointGoesForward, out Vector3 successorPoint) { nextWaypointIndex = -1; nextPointGoesForward = false; float destinationRadius = unit.BehaviorTree.GetBehaviorVariableValue(BehaviorVariableName.Float_RouteWaypointRadius).FloatVal; //Vector3 foundDest; Vector3 lastReachablePoint; Vector3 firstUnreachableWaypoint; List <AbstractActor> lanceUnits = AIUtil.GetLanceUnits(unit.Combat, unit.LanceId); bool completedRoute; findLastReachablePatrolWaypoint(startPosition, patrolRoute, validDestinations, waypointIterator, destinationRadius, out lastReachablePoint, out firstUnreachableWaypoint, out nextWaypointIndex, out completedRoute); successorPoint = startPosition; if (completedRoute) { isComplete = true; nextWaypointIndex = patrolRoute.routePointList.Length - 1; nextPointGoesForward = true; // look away from the foundDest in the direction that we moved // TODO(dlecompte) try to look away from the previous waypoint? Or maybe the pathnode's previous parent? successorPoint = lastReachablePoint + (lastReachablePoint - startPosition); // TODO(dlecompte) this ignores maxDist, probably could prune smarter. return(lastReachablePoint); } Vector3 nextWaypoint = patrolRoute.routePointList[nextWaypointIndex].Position; nextPointGoesForward = waypointIterator.goingForward; successorPoint = nextWaypoint; isComplete = false; return(lastReachablePoint); }
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); }
void findLastReachablePatrolWaypoint(Vector3 startPosition, RouteGameLogic patrolRoute, List <PathNode> pathNodes, PatrolRouteWaypoints waypointIterator, float destinationRadius, out Vector3 lastReachablePoint, out Vector3 firstUnreachableWayPoint, out int nextWaypointIndex, out bool completedRoute) { List <int> indicesConsideredThisTurn = new List <int>(); // to keep us from visiting the same node twice in a turn, either in a loop or in a ping-pong // We can definitely reach the start point lastReachablePoint = startPosition; // The following is just to get past the compiler error of assigning an out param. firstUnreachableWayPoint = startPosition; PathNode tempPathNode = null; PathNode realPathNode = null; foreach (int waypointIndex in waypointIterator.GetWaypoints()) { if (indicesConsideredThisTurn.IndexOf(waypointIndex) >= 0) { // we've already been here nextWaypointIndex = waypointIndex; completedRoute = false; return; } Vector3 wayPoint = patrolRoute.routePointList[waypointIndex].Position; firstUnreachableWayPoint = wayPoint; Vector3 foundPoint; // Try and find if (findClosestWalkablePointToDestination(unit.Combat.HexGrid, wayPoint, startPosition, pathNodes, destinationRadius, out foundPoint, out tempPathNode)) { // If a pathnode was found, update the realPathNode. if (tempPathNode != null) { realPathNode = tempPathNode; } lastReachablePoint = foundPoint; indicesConsideredThisTurn.Add(waypointIndex); } else { // At this point we have a start point we can reach and the next waypoint we can't reach. Try to find // the closest point in the path node to the next waypoint. We're going to find the closest point to the // firstUnreachableWayPoint in our pathNodes that pass through the lastPathNode that we can reach. float closestDistance = AIUtil.Get2DSquaredDistanceBetweenVector3s(lastReachablePoint, firstUnreachableWayPoint); PathNode closestPathNode = realPathNode; // Loop through all our path nodes. for (int i = 0; i < pathNodes.Count; ++i) { // Find the distance from this node to the first unreachable waypoint. PathNode currentPathNode = pathNodes[i]; float currentDistance = AIUtil.Get2DSquaredDistanceBetweenVector3s(currentPathNode.Position, firstUnreachableWayPoint); // If this node is closer to the destination than our current best node if (currentDistance <= closestDistance) { // If we couldn't reach the first node, just move towards the first node as best we can. if (realPathNode == null) { closestPathNode = pathNodes[i]; closestDistance = currentDistance; continue; } // See if this path walks through the previous waypoint. while (currentPathNode != null) { // If so, change our closest node. if (currentPathNode == realPathNode) { closestPathNode = pathNodes[i]; closestDistance = currentDistance; break; } currentPathNode = currentPathNode.Parent; } } } lastReachablePoint = closestPathNode.Position; nextWaypointIndex = waypointIndex; completedRoute = false; return; } } // used up all waypoints nextWaypointIndex = -1; completedRoute = true; }