private void UpdateDistance() { if (_lastUpdated == SimulationManager.instance.m_currentGameTime) { return; } _lastUpdated = SimulationManager.instance.m_currentGameTime; if (!SkylinesOverwatch.Data.Instance.IsHearse(_id) || !Helper.IsBuildingWithDead(_target)) { _distance = float.PositiveInfinity; return; } Building b = Singleton <BuildingManager> .instance.m_buildings.m_buffer[_target]; Vehicle v = Singleton <VehicleManager> .instance.m_vehicles.m_buffer[_id]; _distance = (b.m_position - v.GetLastFramePosition()).sqrMagnitude; if (_distance <= Settings.Instance.ImmediateRange1) { _distance = float.NegativeInfinity; return; } if (v.m_targetBuilding != _target) { _distance = float.PositiveInfinity; return; } }
private void UpdateHearses() { SkylinesOverwatch.Data data = SkylinesOverwatch.Data.Instance; foreach (ushort vehicleID in data.VehiclesRemoved) { if (!data.IsHearse(vehicleID)) { continue; } if (_lasttargets.ContainsKey(vehicleID) && Helper.IsBuildingWithDead(_lasttargets[vehicleID])) { foreach (ushort id in _cemeteries.Keys) { _cemeteries[id].AddPickup(_lasttargets[vehicleID]); } } _oldtargets.Remove(vehicleID); if (_lasttargets.ContainsKey(vehicleID)) { _master.Remove(_lasttargets[vehicleID]); } _lasttargets.Remove(vehicleID); _lastchangetimes.Remove(vehicleID); _PathfindCount.Remove(vehicleID); } if (!SimulationManager.instance.SimulationPaused) { uint num1 = Singleton <SimulationManager> .instance.m_currentFrameIndex >> 4 & 7u; uint num2 = _lastProcessedFrame >> 4 & 7u; foreach (ushort vehicleID in data.VehiclesUpdated) { if (!data.IsHearse(vehicleID)) { continue; } Vehicle v = Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID]; if (!_cemeteries.ContainsKey(v.m_sourceBuilding)) { continue; } if (v.m_flags.IsFlagSet(Vehicle.Flags.Stopped)) { if (!_stopped.Contains(vehicleID)) { Singleton <VehicleManager> .instance.RemoveFromGrid(vehicleID, ref Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID], false); _stopped.Add(vehicleID); } continue; } if (v.m_flags.IsFlagSet(Vehicle.Flags.Stopped) || v.m_flags.IsFlagSet(Vehicle.Flags.WaitingSpace) || v.m_flags.IsFlagSet(Vehicle.Flags.WaitingPath) || v.m_flags.IsFlagSet(Vehicle.Flags.WaitingLoading) || v.m_flags.IsFlagSet(Vehicle.Flags.WaitingCargo)) { continue; } if (!v.m_flags.IsFlagSet(Vehicle.Flags.Spawned)) { continue; } if (v.m_path == 0u) { continue; } _PathfindCount.Remove(vehicleID); if (_stopped.Contains(vehicleID)) { _stopped.Remove(vehicleID); } else if (!v.m_flags.IsFlagSet(Vehicle.Flags.WaitingTarget)) { uint num3 = vehicleID & 7u; if (num1 != num3 && num2 != num3) { _updated.Remove(vehicleID); continue; } else if (_updated.Contains(vehicleID)) { continue; } } _updated.Add(vehicleID); int vehicleStatus = GetHearseStatus(ref v); if (vehicleStatus == VEHICLE_STATUS_HEARSE_RETURN && _lasttargets.ContainsKey(vehicleID)) { if (Helper.IsBuildingWithDead(_lasttargets[vehicleID])) { foreach (ushort id in _cemeteries.Keys) { _cemeteries[id].AddPickup(_lasttargets[vehicleID]); } } _lasttargets.Remove(vehicleID); continue; } if (vehicleStatus != VEHICLE_STATUS_HEARSE_COLLECT && vehicleStatus != VEHICLE_STATUS_HEARSE_WAIT) { continue; } ushort target = _cemeteries[v.m_sourceBuilding].AssignTarget(vehicleID); if (target != 0 && target != v.m_targetBuilding) { if (Helper.IsBuildingWithDead(v.m_targetBuilding)) { foreach (ushort id in _cemeteries.Keys) { _cemeteries[id].AddPickup(v.m_targetBuilding); } } _master.Remove(v.m_targetBuilding); if (vehicleStatus == VEHICLE_STATUS_HEARSE_COLLECT) { _lasttargets[vehicleID] = v.m_targetBuilding; if (_lastchangetimes.ContainsKey(vehicleID)) { _lastchangetimes[vehicleID] = SimulationManager.instance.m_currentGameTime; } else { _lastchangetimes.Add(vehicleID, SimulationManager.instance.m_currentGameTime); } } _CustomHearseAI.SetTarget(vehicleID, ref Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID], target); } else { if (_master.ContainsKey(v.m_targetBuilding)) { if (_master[v.m_targetBuilding].Vehicle != vehicleID) { _master[v.m_targetBuilding] = new Claimant(vehicleID, v.m_targetBuilding); } } else { _master.Add(v.m_targetBuilding, new Claimant(vehicleID, v.m_targetBuilding)); } } } } foreach (ushort vehicleID in data.Hearses) { if (Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID].m_flags.IsFlagSet(Vehicle.Flags.WaitingPath)) { PathManager instance = Singleton <PathManager> .instance; byte pathFindFlags = instance.m_pathUnits.m_buffer[(int)((UIntPtr)Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID].m_path)].m_pathFindFlags; if ((pathFindFlags & 4) != 0) { _PathfindCount.Remove(vehicleID); } else if ((pathFindFlags & 8) != 0) { int vehicleStatus = GetHearseStatus(ref Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID]); if (_lasttargets.ContainsKey(vehicleID)) { Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID].m_flags &= ~Vehicle.Flags.WaitingPath; Singleton <PathManager> .instance.ReleasePath(Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID].m_path); Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID].m_path = 0u; _CustomHearseAI.SetTarget(vehicleID, ref Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID], _lasttargets[vehicleID]); _lasttargets.Remove(vehicleID); } else if ((vehicleStatus == VEHICLE_STATUS_HEARSE_WAIT || vehicleStatus == VEHICLE_STATUS_HEARSE_COLLECT) && (Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID].m_flags.IsFlagSet(Vehicle.Flags.Spawned)) && _cemeteries.ContainsKey(Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID].m_sourceBuilding) && (!_PathfindCount.ContainsKey(vehicleID) || _PathfindCount[vehicleID] < 20)) { if (!_PathfindCount.ContainsKey(vehicleID)) { _PathfindCount[vehicleID] = 0; } _PathfindCount[vehicleID]++; ushort target = _cemeteries[Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID].m_sourceBuilding].GetUnclaimedTarget(vehicleID); if (target == 0) { _PathfindCount[vehicleID] = ushort.MaxValue; } else { if (Dispatcher._oldtargets != null) { if (!Dispatcher._oldtargets.ContainsKey(vehicleID)) { Dispatcher._oldtargets.Add(vehicleID, new HashSet <ushort>()); } Dispatcher._oldtargets[vehicleID].Add(target); } Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID].m_flags &= ~Vehicle.Flags.WaitingPath; Singleton <PathManager> .instance.ReleasePath(Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID].m_path); Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID].m_path = 0u; _CustomHearseAI.SetTarget(vehicleID, ref Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID], target); } } } } } }
public void SetTarget(ushort vehicleID, ref Vehicle data, ushort targetBuilding) { if (!data.m_flags.IsFlagSet(Vehicle.Flags.Spawned)) { if (Identity.ModConf.MinimizeHearses) { if (Dispatcher._cemeteries != null && Dispatcher._cemeteries.ContainsKey(data.m_sourceBuilding)) { if (Dispatcher._cemeteries[data.m_sourceBuilding]._primary.Count > 0 || Dispatcher._cemeteries[data.m_sourceBuilding]._secondary.Count > 0 || Dispatcher._cemeteries[data.m_sourceBuilding]._checkups.Count > 0) { if ((!Dispatcher._cemeteries[data.m_sourceBuilding]._primary.Contains(targetBuilding) && !Dispatcher._cemeteries[data.m_sourceBuilding]._secondary.Contains(targetBuilding)) || !Helper.IsBuildingWithDead(targetBuilding)) { data.Unspawn(vehicleID); return; } } } else { data.Unspawn(vehicleID); return; } } if (Dispatcher._cemeteries != null && Dispatcher._cemeteries.ContainsKey(data.m_sourceBuilding)) { int max, now; Dispatcher._cemeteries[data.m_sourceBuilding].CaluculateWorkingVehicles(out max, out now); if (now > max) { data.Unspawn(vehicleID); return; } } } BuildingManager instance = Singleton <BuildingManager> .instance; ushort current = data.m_targetBuilding; uint path = data.m_path; byte pathPositionIndex = data.m_pathPositionIndex; byte lastPathOffset = data.m_lastPathOffset; ushort target = targetBuilding; int vehicleStatus = Dispatcher.GetHearseStatus(ref data); int retry_max = 1; if (vehicleStatus == Dispatcher.VEHICLE_STATUS_HEARSE_WAIT) { if (Dispatcher._oldtargets != null) { Dispatcher._oldtargets.Remove(vehicleID); } retry_max = 20; } for (int retry = 0; retry < retry_max; retry++) { if (retry > 0) { if (Dispatcher._cemeteries == null || !Dispatcher._cemeteries.ContainsKey(data.m_sourceBuilding)) { break; } target = Dispatcher._cemeteries[data.m_sourceBuilding].GetUnclaimedTarget(vehicleID); if (target == 0) { break; } if (Dispatcher._oldtargets != null) { if (!Dispatcher._oldtargets.ContainsKey(vehicleID)) { Dispatcher._oldtargets.Add(vehicleID, new HashSet <ushort>()); } Dispatcher._oldtargets[vehicleID].Add(target); } } this.RemoveTarget(vehicleID, ref data); data.m_targetBuilding = targetBuilding; data.m_flags &= ~Vehicle.Flags.WaitingTarget; data.m_waitCounter = 0; if (targetBuilding != 0) { instance.m_buildings.m_buffer[(int)targetBuilding].AddGuestVehicle(vehicleID, ref data); } else { if (data.m_flags.IsFlagSet(Vehicle.Flags.TransferToTarget)) { if (data.m_transferSize > 0) { TransferManager.TransferOffer offer = default(TransferManager.TransferOffer); offer.Priority = 7; offer.Vehicle = vehicleID; if (data.m_sourceBuilding != 0) { offer.Position = (data.GetLastFramePosition() + Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)data.m_sourceBuilding].m_position) * 0.5f; } else { offer.Position = data.GetLastFramePosition(); } offer.Amount = 1; offer.Active = true; Singleton <TransferManager> .instance.AddOutgoingOffer((TransferManager.TransferReason) data.m_transferType, offer); data.m_flags |= Vehicle.Flags.WaitingTarget; } else { data.m_flags |= Vehicle.Flags.GoingBack; } } if (data.m_flags.IsFlagSet(Vehicle.Flags.TransferToSource)) { VehicleInfo m_info = Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID].Info; int num = ((HearseAI)m_info.m_vehicleAI).m_corpseCapacity; if (this.ShouldReturnToSource(vehicleID, ref data)) { num = (int)data.m_transferSize; } else if (data.m_sourceBuilding != 0) { BuildingInfo info = instance.m_buildings.m_buffer[(int)data.m_sourceBuilding].Info; if (info == null) { return; } int num2; int num3; info.m_buildingAI.GetMaterialAmount(data.m_sourceBuilding, ref instance.m_buildings.m_buffer[(int)data.m_sourceBuilding], TransferManager.TransferReason.Dead, out num2, out num3); num = Mathf.Min(num, num3 - num2); } if ((int)data.m_transferSize < num) { TransferManager.TransferOffer offer2 = default(TransferManager.TransferOffer); offer2.Priority = 7; offer2.Vehicle = vehicleID; if (data.m_sourceBuilding != 0) { offer2.Position = (data.GetLastFramePosition() + Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)data.m_sourceBuilding].m_position) * 0.5f; } else { offer2.Position = data.GetLastFramePosition(); } offer2.Amount = 1; offer2.Active = true; Singleton <TransferManager> .instance.AddIncomingOffer((TransferManager.TransferReason) data.m_transferType, offer2); data.m_flags |= Vehicle.Flags.WaitingTarget; } else { data.m_flags |= Vehicle.Flags.GoingBack; } } } if ((targetBuilding == 0 || (vehicleStatus != Dispatcher.VEHICLE_STATUS_HEARSE_COLLECT && vehicleStatus != Dispatcher.VEHICLE_STATUS_HEARSE_WAIT))) { if (!StartPathFind(vehicleID, ref data)) { data.Unspawn(vehicleID); } return; } if (StartPathFind(vehicleID, ref Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID])) { if (Dispatcher._oldtargets != null) { if (!Dispatcher._oldtargets.ContainsKey(vehicleID)) { Dispatcher._oldtargets.Add(vehicleID, new HashSet <ushort>()); } Dispatcher._oldtargets[vehicleID].Add(target); } if (Dispatcher._master != null) { if (Dispatcher._master.ContainsKey(target)) { if (Dispatcher._master[target].Vehicle != vehicleID) { Dispatcher._master[target] = new Claimant(vehicleID, target); } } else if (target != 0) { Dispatcher._master.Add(target, new Claimant(vehicleID, target)); } } return; } } if (vehicleStatus == Dispatcher.VEHICLE_STATUS_HEARSE_COLLECT) { target = current; RemoveTarget(vehicleID, ref Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID]); Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID].m_targetBuilding = target; Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID].m_path = path; Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID].m_pathPositionIndex = pathPositionIndex; Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID].m_lastPathOffset = lastPathOffset; Singleton <BuildingManager> .instance.m_buildings.m_buffer[(int)current].AddGuestVehicle(vehicleID, ref Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID]); if (Dispatcher._master != null) { if (Dispatcher._master.ContainsKey(target)) { if (Dispatcher._master[target].Vehicle != vehicleID) { Dispatcher._master[target] = new Claimant(vehicleID, target); } } else if (target != 0) { Dispatcher._master.Add(target, new Claimant(vehicleID, target)); } } } else { Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID].Unspawn(vehicleID); } }
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); }
public ushort AssignTarget(ushort vehicleID) { Vehicle vehicle = Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleID]; ushort target = 0; if (vehicle.m_sourceBuilding != _buildingID) { return(target); } if (Singleton <PathManager> .instance.m_pathUnits.m_buffer[vehicle.m_path].m_nextPathUnit == 0) { byte b = vehicle.m_pathPositionIndex; if (b == 255) { b = 0; } if ((b & 1) == 0) { b += 1; } if ((b >> 1) + 1 >= Singleton <PathManager> .instance.m_pathUnits.m_buffer[vehicle.m_path].m_positionCount) { return(target); } } ushort current = vehicle.m_targetBuilding; if (!Helper.IsBuildingWithDead(current)) { _oldtargets.Remove(vehicleID); _master.Remove(current); _primary.Remove(current); _secondary.Remove(current); current = 0; } else if (_master.ContainsKey(current)) { if (_master[current].IsValid && _master[current].Vehicle != vehicleID) { current = 0; } } int vehicleStatus = Dispatcher.GetHearseStatus(ref vehicle); if (current != 0 && vehicleStatus == Dispatcher.VEHICLE_STATUS_HEARSE_COLLECT && _lastchangetimes.ContainsKey(vehicleID) && (SimulationManager.instance.m_currentGameTime - _lastchangetimes[vehicleID]).TotalDays < 0.5) { return(target); } bool immediateOnly = (_primary.Contains(current) || _secondary.Contains(current)); SearchDirection immediateDirection = GetImmediateSearchDirection(vehicleID); if (immediateOnly && immediateDirection == SearchDirection.None) { target = current; } else { target = GetClosestTarget(vehicleID, ref _primary, immediateOnly, immediateDirection); if (target == 0) { target = GetClosestTarget(vehicleID, ref _secondary, immediateOnly, immediateDirection); } } if (target == 0) { _oldtargets.Remove(vehicleID); if ((vehicle.m_targetBuilding != 0 && WithinPrimaryRange(vehicle.m_targetBuilding)) || _checkups.Count == 0) { target = vehicle.m_targetBuilding; } else { target = _checkups[0]; _checkups.RemoveAt(0); } } return(target); }
private ushort GetUnclaimedTarget(ICollection <ushort> targets, ushort vehicleID) { Building[] buildings = Singleton <BuildingManager> .instance.m_buildings.m_buffer; List <ushort> removals = new List <ushort>(); ushort target = 0; int targetProblematicLevel = 0; float distance = float.PositiveInfinity; Building landfill = buildings[(int)_buildingID]; foreach (ushort id in targets) { if (target == id) { continue; } if (_oldtargets.ContainsKey(vehicleID) && _oldtargets[vehicleID].Contains(id)) { continue; } if (!Helper.IsBuildingWithDead(id)) { removals.Add(id); continue; } Vector3 p = buildings[id].m_position; float d = (p - landfill.m_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 (_master.ContainsKey(id) && _master[id].IsValid) { continue; } else { if (targetProblematicLevel > candidateProblematicLevel) { continue; } if (targetProblematicLevel < candidateProblematicLevel) { // No additonal conditions at the moment. Problematic buildings always have priority over nonproblematic buildings } else { if (d > distance) { continue; } } } target = id; targetProblematicLevel = candidateProblematicLevel; distance = d; } foreach (ushort id in removals) { _master.Remove(id); targets.Remove(id); } return(target); }