/// <summary> /// Determines whether the specified vehicle has a problem. /// </summary> /// <param name="vehicleId">The vehicle identifier.</param> /// <param name="vehicle">The vehicle.</param> /// <returns> /// True if the vehicle has at least one problem. /// </returns> public static bool HasProblem(ushort vehicleId, ref Vehicle vehicle) { // Don't check unspawned vehicles. if (vehicle.Info == null || (vehicle.m_flags & Vehicle.Flags.Spawned) == ~VehicleHelper.VehicleAll) { return(false); } // Cargo parent? if (vehicle.m_cargoParent != 0 && !Global.Settings.Experimental.AllowTrackingOfCargoChildren) { return(false); } // Trailer? if (vehicle.m_leadingVehicle != 0) { if (!Global.Settings.Experimental.TrackLostTrailers) { return(false); } return(TrailerHasProblem(vehicleId, ref vehicle)); } // Only check vehicles we dispatch unless told to check other vehicles as well. if (!(Global.Settings.RecoveryCrews.DispatchVehicles || IsDispatchersResponsibility(ref vehicle))) { return(false); } // Check vehicles flags. if ((vehicle.m_flags & FlagsToCheck) != ~VehicleHelper.VehicleAll) { return(true); } if (ConfusionHelper.VehicleIsConfused(ref vehicle)) { return(true); } return(false); }
/// <summary> /// Updates the specified vehicle. /// </summary> /// <param name="vehicle">The vehicle.</param> public void Update(ref Vehicle vehicle) { this.targetBuildingId = vehicle.m_targetBuilding; this.isTrailer = vehicle.m_leadingVehicle != 0; this.hasCargoParent = vehicle.m_cargoParent != 0; if (this.hasCargoParent && !Global.Settings.Experimental.AllowTrackingOfCargoChildren) { return; } if (this.isTrailer) { if (Global.Settings.Experimental.TrackLostTrailers) { this.UpdateTrailer(ref vehicle); } return; } // Check if vehicle has flag that should be checked. Vehicle.Flags flags = vehicle.m_flags & FlagsToCheck; if ((flags & VehicleHelper.VehicleAll) != ~VehicleHelper.VehicleAll) { Vector3 position = vehicle.GetLastFramePosition(); // Remember first time stamp the vehicle was seen with this flag at this position. if (this.checkFlagSinceFrame == 0 || this.checkFlagSinceTime == 0 || flags != this.checkFlags || Math.Truncate((position - this.checkFlagPosition).sqrMagnitude) > 0) { this.isFlagged = false; this.checkFlags = flags; this.checkFlagPosition = position; this.checkFlagSinceTime = Global.SimulationTime; this.checkFlagSinceFrame = Global.CurrentFrame; } else if (!this.isFlagged && this.CheckFlaggedForFrames > Global.CheckFlagStuckDelay) { // Check if stuck with flag. double delta = this.CheckFlaggedForSeconds; if (delta > Global.Settings.RecoveryCrews.DelaySeconds) { Log.Info(this, "IsFlagged", this.checkFlags, this.VehicleId, delta, VehicleHelper.GetVehicleName(this.VehicleId)); this.isFlagged = true; } } } else if ((this.checkFlags & VehicleHelper.VehicleAll) != ~VehicleHelper.VehicleAll || this.checkFlagSinceTime != 0 || this.checkFlagSinceFrame != 0) { this.isFlagged = false; this.checkFlags = ~VehicleHelper.VehicleAll; this.checkFlagSinceTime = 0; this.checkFlagSinceFrame = 0; } // Check if vehicle is confused. if (ConfusionHelper.VehicleIsConfused(ref vehicle)) { if (this.confusedDeAssignedSinceFrame == 0) { this.confusedDeAssignedSinceFrame = Global.CurrentFrame; } if (this.confusedSinceFrame == 0 || this.confusedSinceTime == 0) { if (Log.LogALot) { Log.DevDebug(this, "Update", "NewConfused", this.VehicleId, this.ConfusedForSeconds, this.ConfusedForFrames, Global.Settings.RecoveryCrews.DelaySeconds, Global.DeAssignConfusedDelay, vehicle.m_targetBuilding, vehicle.m_flags, VehicleHelper.GetVehicleName(this.VehicleId)); } this.isConfused = false; this.confusedSinceTime = Global.SimulationTime; this.confusedSinceFrame = Global.CurrentFrame; this.confusedDeAssignedSinceFrame = Global.CurrentFrame; } else if (!this.isConfused && this.ConfusedForFrames > Global.CheckFlagStuckDelay) { // Check if stuck confused. double delta = this.ConfusedForSeconds; if (delta > Global.Settings.RecoveryCrews.DelaySeconds) { Log.Info(this, "IsConfused", this.VehicleId, delta, VehicleHelper.GetVehicleName(this.VehicleId)); this.isConfused = true; } } } else if (this.confusedSinceTime != 0 || this.confusedSinceFrame != 0 || this.confusedDeAssignedSinceFrame != 0) { this.isConfused = false; this.confusedSinceTime = 0; this.confusedSinceFrame = 0; this.confusedDeAssignedSinceFrame = 0; } this.isStuck = this.isLost || this.isConfused || this.isFlagged || this.isBroken; }
/// <summary> /// Categorizes the vehicles. /// </summary> /// <param name="firstVehicleId">The first vehicle identifier.</param> /// <param name="lastVehicleId">The last vehicle identifier.</param> private void HandleVehicles(ushort firstVehicleId, int lastVehicleId) { Vehicle[] vehicles = Singleton <VehicleManager> .instance.m_vehicles.m_buffer; Building[] buildings = Singleton <BuildingManager> .instance.m_buildings.m_buffer; for (ushort id = firstVehicleId; id < lastVehicleId; id++) { // Is the vehicle? if (vehicles[id].m_leadingVehicle != 0 || vehicles[id].m_cargoParent != 0 || vehicles[id].Info == null || (vehicles[id].m_flags & VehicleHelper.VehicleExists) == ~VehicleHelper.VehicleAll) { if (this.removedFromGrid != null && this.removedFromGrid.Contains(id)) { this.removedFromGrid.Remove(id); } if (this.StuckVehicles != null && this.StuckVehicles.ContainsKey(id)) { //if (Log.LogALot) //{ // Log.DevDebug(this, "HandleVehicles", "StuckVehicles", "Gone", id); //} this.StuckVehicles.Remove(id); } } else { // Check target assignments for service vehicles. if ((vehicles[id].m_flags & Vehicle.Flags.TransferToSource) != ~VehicleHelper.VehicleAll && (vehicles[id].m_flags & (Vehicle.Flags.TransferToTarget | Vehicle.Flags.Arriving | Vehicle.Flags.Stopped)) == ~VehicleHelper.VehicleAll && (vehicles[id].m_flags & VehicleHelper.VehicleUnavailable) == ~VehicleHelper.VehicleAll && vehicles[id].m_targetBuilding != vehicles[id].m_sourceBuilding && (buildings[vehicles[id].m_sourceBuilding].m_flags & Building.Flags.Downgrading) == Building.Flags.None) { if (Global.Settings.DeathCare.DispatchVehicles && Global.HearseDispatcher != null && vehicles[id].m_transferType == Global.HearseDispatcher.TransferType) { Global.HearseDispatcher.CheckVehicleTarget(id, ref vehicles[id]); } if (Global.Settings.Garbage.DispatchVehicles && Global.GarbageTruckDispatcher != null && vehicles[id].m_transferType == Global.GarbageTruckDispatcher.TransferType) { Global.GarbageTruckDispatcher.CheckVehicleTarget(id, ref vehicles[id]); } if (Global.Settings.HealthCare.DispatchVehicles && Global.AmbulanceDispatcher != null && vehicles[id].m_transferType == Global.AmbulanceDispatcher.TransferType) { Global.AmbulanceDispatcher.CheckVehicleTarget(id, ref vehicles[id]); } } // Handle grid removals. if (this.removedFromGrid != null) { if ((vehicles[id].m_flags & Vehicle.Flags.Stopped) == ~VehicleHelper.VehicleAll && (vehicles[id].Info.m_vehicleAI is HearseAI || vehicles[id].Info.m_vehicleAI is AmbulanceAI)) { if (this.removedFromGrid.Contains(id)) { if (Log.LogALot) { Log.Debug(this, "HandleVehicles", "Moving", id, vehicles[id].m_targetBuilding, vehicles[id].Info.name, VehicleHelper.GetVehicleName(id), vehicles[id].m_flags); } this.removedFromGrid.Remove(id); } } else if ((Global.Settings.DeathCare.RemoveFromGrid && vehicles[id].Info.m_vehicleAI is HearseAI) || (Global.Settings.HealthCare.RemoveFromGrid && vehicles[id].Info.m_vehicleAI is AmbulanceAI)) { if (!this.removedFromGrid.Contains(id)) { if (Log.LogALot) { Log.Debug(this, "HandleVehicles", "RemoveFromGrid", id, vehicles[id].m_targetBuilding, vehicles[id].Info.name, VehicleHelper.GetVehicleName(id), vehicles[id].m_flags); } Singleton <VehicleManager> .instance.RemoveFromGrid(id, ref vehicles[id], false); this.removedFromGrid.Add(id); } } } // Try to fix stuck vehicles. if (this.StuckVehicles != null) { if (StuckVehicleInfo.HasProblem(id, ref vehicles[id])) { StuckVehicleInfo stuckVehicle; if (this.StuckVehicles.TryGetValue(id, out stuckVehicle)) { stuckVehicle.Update(ref vehicles[id]); } else { stuckVehicle = new StuckVehicleInfo(id, ref vehicles[id]); this.StuckVehicles[id] = stuckVehicle; if (Log.LogALot) { Log.DevDebug(this, "HandleVehicles", "StuckVehicles", "New", id, vehicles[id].m_flags, stuckVehicle.Flagged, stuckVehicle.Lost, stuckVehicle.Confused, stuckVehicle.ExtraInfo); } } if (stuckVehicle.HandleProblem()) { if (Log.LogALot) { Log.DevDebug(this, "HandleVehicles", "StuckVehicles", "Handled", id); } this.StuckVehicles.Remove(id); } } else if (this.StuckVehicles.ContainsKey(id)) { if (Log.LogALot) { Log.DevDebug(this, "HandleVehicles", "StuckVehicles", "NoProblem", id, vehicles[id].m_flags, vehicles[id].m_flags & StuckVehicleInfo.FlagsToCheck, ConfusionHelper.VehicleIsConfused(ref vehicles[id])); } this.StuckVehicles.Remove(id); } } } } }