Pair <CPos, SubCell>?PopPath(Actor self) { if (path.Count == 0) { return(null); } var nextCell = path[path.Count - 1]; // Something else might have moved us, so the path is no longer valid. if (!Util.AreAdjacentCells(mobile.ToCell, nextCell)) { path = EvalPath(BlockedByActor.Immovable); return(null); } var containsTemporaryBlocker = WorldUtils.ContainsTemporaryBlocker(self.World, nextCell, self); // Next cell in the move is blocked by another actor if (containsTemporaryBlocker || !mobile.CanEnterCell(nextCell, ignoreActor)) { // Are we close enough? var cellRange = nearEnough.Length / 1024; if (!containsTemporaryBlocker && (mobile.ToCell - destination.Value).LengthSquared <= cellRange * cellRange && mobile.CanStayInCell(mobile.ToCell)) { // Apply some simple checks to avoid giving up in cases where we can be confident that // nudging/waiting/repathing should produce better results. // Avoid fighting over the destination cell if (path.Count < 2) { path.Clear(); return(null); } // We can reasonably assume that the blocker is friendly and has a similar locomotor type. // If there is a free cell next to the blocker that is a similar or closer distance to the // destination then we can probably nudge or path around it. var blockerDistSq = (nextCell - destination.Value).LengthSquared; var nudgeOrRepath = CVec.Directions .Select(d => nextCell + d) .Any(c => c != self.Location && (c - destination.Value).LengthSquared <= blockerDistSq && mobile.CanEnterCell(c, ignoreActor)); if (!nudgeOrRepath) { path.Clear(); return(null); } } // There is no point in waiting for the other actor to move if it is incapable of moving. if (!mobile.CanEnterCell(nextCell, ignoreActor, BlockedByActor.Immovable)) { path = EvalPath(BlockedByActor.Immovable); return(null); } // See if they will move self.NotifyBlocker(nextCell); // Wait a bit to see if they leave if (!hasWaited) { waitTicksRemaining = mobile.Info.LocomotorInfo.WaitAverage; hasWaited = true; return(null); } if (--waitTicksRemaining >= 0) { return(null); } hasWaited = false; // If the blocking actors are already leaving, wait a little longer instead of repathing if (CellIsEvacuating(self, nextCell)) { return(null); } // Calculate a new path mobile.RemoveInfluence(); var newPath = EvalPath(BlockedByActor.All); mobile.AddInfluence(); if (newPath.Count != 0) { path = newPath; var newCell = path[path.Count - 1]; path.RemoveAt(path.Count - 1); return(Pair.New(newCell, mobile.GetAvailableSubCell(nextCell, mobile.FromSubCell, ignoreActor))); } else if (mobile.IsBlocking) { // If there is no way around the blocker and blocker will not move and we are blocking others, back up to let others pass. var newCell = mobile.GetAdjacentCell(nextCell); if (newCell != null) { if ((nextCell - newCell).Value.LengthSquared > 2) { path.Add(mobile.ToCell); } return(Pair.New(newCell.Value, mobile.GetAvailableSubCell(newCell.Value, mobile.FromSubCell, ignoreActor))); } } return(null); } hasWaited = false; path.RemoveAt(path.Count - 1); return(Pair.New(nextCell, mobile.GetAvailableSubCell(nextCell, mobile.FromSubCell, ignoreActor))); }
Pair <CPos, SubCell>?PopPath(Actor self) { if (path.Count == 0) { return(null); } var nextCell = path[path.Count - 1]; var containsTemporaryBlocker = WorldUtils.ContainsTemporaryBlocker(self.World, nextCell, self); //Next cell in the move is blocked by another actor. if (containsTemporaryBlocker || !mobile.CanEnterCell(nextCell, ignoreActor, true)) { //Are we close enough? var cellRange = nearEnough.Length / 1024; if (!containsTemporaryBlocker && (mobile.ToCell - destination.Value).LengthSquard <= cellRange * cellRange) { path.Clear(); return(null); } //See if they will move if (!hasNotifiedBlocker) { self.NotifyBlocker(nextCell); hasNotifiedBlocker = true; } //Wait a bit to see if they leave if (!hasWaited) { waitTicksRemaining = mobile.Info.WaitAverage + self.World.SharedRandom.Next(-mobile.Info.WaitSpread, mobile.Info.WaitSpread); hasWaited = true; } if (--waitTicksRemaining >= 0) { return(null); } if (mobile.TicksBeforePathing > 0) { mobile.TicksBeforePathing--; return(null); } //Calculate a new path mobile.RemoveInfluence(); var newPath = EvalPath(); mobile.AddInfluence(); if (newPath.Count != 0) { path = newPath; } return(null); } hasNotifiedBlocker = false; hasWaited = false; path.RemoveAt(path.Count - 1); var subCell = mobile.GetAvailableSubCell(nextCell, SubCell.Any, ignoreActor); return(Pair.New(nextCell, subCell)); }
Pair <CPos, SubCell>?PopPath(Actor self) { if (path.Count == 0) { return(null); } var nextCell = path[path.Count - 1]; // Something else might have moved us, so the path is no longer valid. if (!Util.AreAdjacentCells(mobile.ToCell, nextCell)) { path = EvalPath(BlockedByActor.Immovable); return(null); } var containsTemporaryBlocker = WorldUtils.ContainsTemporaryBlocker(self.World, nextCell, self); // Next cell in the move is blocked by another actor if (containsTemporaryBlocker || !mobile.CanEnterCell(nextCell, ignoreActor)) { // Are we close enough? var cellRange = nearEnough.Length / 1024; if (!containsTemporaryBlocker && (mobile.ToCell - destination.Value).LengthSquared <= cellRange * cellRange) { path.Clear(); return(null); } // There is no point in waiting for the other actor to move if it is incapable of moving. if (!mobile.CanEnterCell(nextCell, ignoreActor, BlockedByActor.Immovable)) { path = EvalPath(BlockedByActor.Immovable); return(null); } // See if they will move self.NotifyBlocker(nextCell); // Wait a bit to see if they leave if (!hasWaited) { waitTicksRemaining = mobile.Info.LocomotorInfo.WaitAverage; hasWaited = true; return(null); } if (--waitTicksRemaining >= 0) { return(null); } hasWaited = false; // If the blocking actors are already leaving, wait a little longer instead of repathing if (CellIsEvacuating(self, nextCell)) { return(null); } // Calculate a new path mobile.RemoveInfluence(); var newPath = EvalPath(BlockedByActor.All); mobile.AddInfluence(); if (newPath.Count != 0) { path = newPath; var newCell = path[path.Count - 1]; path.RemoveAt(path.Count - 1); return(Pair.New(newCell, mobile.GetAvailableSubCell(nextCell, SubCell.Any, ignoreActor))); } else if (mobile.IsBlocking) { // If there is no way around the blocker and blocker will not move and we are blocking others, back up to let others pass. var newCell = mobile.GetAdjacentCell(nextCell); if (newCell != null) { if ((nextCell - newCell).Value.LengthSquared > 2) { path.Add(mobile.ToCell); } return(Pair.New(newCell.Value, mobile.GetAvailableSubCell(newCell.Value, SubCell.Any, ignoreActor))); } } return(null); } hasWaited = false; path.RemoveAt(path.Count - 1); return(Pair.New(nextCell, mobile.GetAvailableSubCell(nextCell, SubCell.Any, ignoreActor))); }