private ushort GetClosestTarget(ushort hearseID, ref HashSet <ushort> targets, bool immediateOnly, SearchDirection immediateDirection) { Vehicle hearse = Singleton <VehicleManager> .instance.m_vehicles.m_buffer[hearseID]; Building[] buildings = Singleton <BuildingManager> .instance.m_buildings.m_buffer; List <ushort> removals = new List <ushort>(); ushort target = hearse.m_targetBuilding; if (_master.ContainsKey(target) && _master[target].IsValid && _master[target].Hearse != hearseID) { target = 0; } bool targetProblematic = false; float distance = float.PositiveInfinity; Vector3 velocity = hearse.GetLastFrameVelocity(); Vector3 position = hearse.GetLastFramePosition(); double bearing = double.PositiveInfinity; double facing = Math.Atan2(velocity.z, velocity.x); if (targets.Contains(target)) { if (!SkylinesOverwatch.Data.Instance.IsBuildingWithDead(target)) { removals.Add(target); target = 0; } else { targetProblematic = (buildings[target].m_problems & Notification.Problem.Death) != Notification.Problem.None; Vector3 a = buildings[target].m_position; distance = (a - position).sqrMagnitude; bearing = Math.Atan2(a.z - position.z, a.x - position.x); } } else if (!immediateOnly) { target = 0; } foreach (ushort id in targets) { if (target == id) { continue; } if (!SkylinesOverwatch.Data.Instance.IsBuildingWithDead(id)) { removals.Add(id); continue; } if (_master.ContainsKey(id) && _master[id].IsValid && !_master[id].IsChallengable) { continue; } Vector3 p = buildings[id].m_position; float d = (p - position).sqrMagnitude; bool candidateProblematic = (buildings[id].m_problems & Notification.Problem.Death) != Notification.Problem.None; double angle = Helper.GetAngleDifference(facing, Math.Atan2(p.z - position.z, p.x - position.x)); bool isImmediate = IsImmediate(d, angle, immediateDirection); #region debug string bname = Singleton <BuildingManager> .instance.GetBuildingName(id, new InstanceID { Building = id }); string vname = Singleton <VehicleManager> .instance.GetVehicleName(hearseID); if (bname.Contains("##") && vname.Contains("##")) { Helper.Instance.NotifyPlayer(String.Format("{0} :: {1} :: {2} :: {3}", d, angle, immediateDirection, isImmediate)); } #endregion if (_master.ContainsKey(id) && _master[id].IsValid && _master[id].IsChallengable) { if (d > distance) { continue; } if (d > _master[id].Distance) { continue; } if (!isImmediate) { continue; } } else { if (immediateOnly && !isImmediate) { continue; } if (targetProblematic && !candidateProblematic) { continue; } if (!targetProblematic && candidateProblematic) { // No additonal conditions at the moment. Problematic buildings always have priority over nonproblematic buildings } else { if (d > distance) { continue; } if (isImmediate) { // If it's that close, no need to further qualify its priority } else if (IsAlongTheWay(d, angle)) { // If it's in the general direction the vehicle is facing, it's good enough } else if (!double.IsPositiveInfinity(bearing)) { angle = Helper.GetAngleDifference(bearing, Math.Atan2(p.z - position.z, p.x - position.x)); if (IsAlongTheWay(d, angle)) { // If it's in the general direction along the vehicle's target path, we will have to settle for it at this point } else { continue; } } else { // If it's not closeby and not in the direction the vehicle is facing, but our vehicle also has no bearing, we will take whatever is out there } } } target = id; targetProblematic = candidateProblematic; distance = d; } foreach (ushort id in removals) { _master.Remove(id); targets.Remove(id); } return(target); }
private ushort GetClosestTarget(ushort vehicleID, ref HashSet <ushort> targets, bool immediateOnly, SearchDirection immediateDirection) { Vehicle vehicle = Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID]; Building[] buildings = Singleton <BuildingManager> .instance.m_buildings.m_buffer; List <ushort> removals = new List <ushort>(); ushort target = vehicle.m_targetBuilding; if (_master.ContainsKey(target) && _master[target].IsValid && _master[target].Vehicle != vehicleID) { target = 0; } int targetProblematicLevel = 0; float targetdistance = float.PositiveInfinity; float distance = float.PositiveInfinity; Vector3 velocity = vehicle.GetLastFrameVelocity(); Vector3 position = vehicle.GetLastFramePosition(); double bearing = double.PositiveInfinity; double facing = Math.Atan2(velocity.z, velocity.x); if (targets.Contains(target)) { if (!Helper.IsBuildingWithDead(target)) { removals.Add(target); target = 0; } else { if ((buildings[target].m_problems & Notification.Problem.Death) != Notification.Problem.None) { if (Identity.ModConf.PrioritizeTargetWithRedSigns && (buildings[target].m_problems & Notification.Problem.MajorProblem) != Notification.Problem.None) { targetProblematicLevel = 2; } else { targetProblematicLevel = 1; } } Vector3 a = buildings[target].m_position; targetdistance = distance = (a - position).sqrMagnitude; bearing = Math.Atan2(a.z - position.z, a.x - position.x); } } else if (!immediateOnly) { target = 0; } foreach (ushort id in targets) { if (target == id) { continue; } if (!Helper.IsBuildingWithDead(id)) { removals.Add(id); continue; } if (_master.ContainsKey(id) && _master[id].IsValid && !_master[id].IsChallengable) { continue; } if (_master.ContainsKey(id) && _master[id].IsValid && _master[id].Vehicle != vehicleID) { Vehicle vehicle2 = Singleton <VehicleManager> .instance.m_vehicles.m_buffer[_master[id].Vehicle]; if (vehicle2.m_flags.IsFlagSet(Vehicle.Flags.Spawned) && vehicle2.m_path != 0 && Singleton <PathManager> .instance.m_pathUnits.m_buffer[vehicle2.m_path].m_nextPathUnit == 0) { byte b = vehicle2.m_pathPositionIndex; if (b == 255) { b = 0; } if ((b & 1) == 0) { b += 1; } if ((b >> 1) + 1 >= Singleton <PathManager> .instance.m_pathUnits.m_buffer[vehicle2.m_path].m_positionCount) { continue; } } } Vector3 p = buildings[id].m_position; float d = (p - position).sqrMagnitude; int candidateProblematicLevel = 0; if ((buildings[id].m_problems & Notification.Problem.Death) != Notification.Problem.None) { if (Identity.ModConf.PrioritizeTargetWithRedSigns && (buildings[id].m_problems & Notification.Problem.MajorProblem) != Notification.Problem.None) { candidateProblematicLevel = 2; } else { candidateProblematicLevel = 1; } } if (_oldtargets.ContainsKey(vehicleID) && _oldtargets[vehicleID].Count > 5 && targetProblematicLevel >= candidateProblematicLevel) { continue; } if (_master.ContainsKey(id) && _master[id].IsValid && _master[id].IsChallengable) { if (targetProblematicLevel > candidateProblematicLevel) { continue; } if (d > targetdistance * 0.9) { continue; } if (d > distance) { continue; } if (d > _master[id].Distance * 0.9) { continue; } double angle = Helper.GetAngleDifference(facing, Math.Atan2(p.z - position.z, p.x - position.x)); int immediateLevel = GetImmediateLevel(d, angle, immediateDirection); if (immediateLevel == 0) { continue; } if (_oldtargets.ContainsKey(vehicleID) && _oldtargets[vehicleID].Contains(id)) { continue; } } else { double angle = Helper.GetAngleDifference(facing, Math.Atan2(p.z - position.z, p.x - position.x)); int immediateLevel = GetImmediateLevel(d, angle, immediateDirection); if (immediateOnly && immediateLevel == 0) { continue; } if (_oldtargets.ContainsKey(vehicleID) && _oldtargets[vehicleID].Contains(id)) { continue; } if (targetProblematicLevel > candidateProblematicLevel) { continue; } if (targetProblematicLevel < candidateProblematicLevel) { // No additonal conditions at the moment. Problematic buildings always have priority over nonproblematic buildings } else { if (d > targetdistance * 0.9) { continue; } if (d > distance) { continue; } if (immediateLevel > 0) { // If it's that close, no need to further qualify its priority } else if (IsAlongTheWay(d, angle)) { // If it's in the general direction the vehicle is facing, it's good enough } else if (!double.IsPositiveInfinity(bearing)) { if (IsAlongTheWay(d, Helper.GetAngleDifference(bearing, Math.Atan2(p.z - position.z, p.x - position.x)))) { // If it's in the general direction along the vehicle's target path, we will have to settle for it at this point } else { continue; } } else { // If it's not closeby and not in the direction the vehicle is facing, but our vehicle also has no bearing, we will take whatever is out there } } } target = id; targetProblematicLevel = candidateProblematicLevel; distance = d; } foreach (ushort id in removals) { _master.Remove(id); targets.Remove(id); } return(target); }