/// <summary> /// Assigns a vehicle to a target building. /// </summary> /// <param name="targetBuilding">The target building.</param> /// <param name="ignoreRange">If set to <c>true</c> ignore the building range.</param> /// <param name="allowCreateSpares">If set to <c>true</c> allow creation of spare vehicles.</param> /// <returns> /// True if vehicle was assigned. /// </returns> private bool AssignVehicle(TargetBuildingInfo targetBuilding, bool ignoreRange, bool allowCreateSpares) { // Get target district. byte targetDistrict = 0; if (this.serviceSettings.DispatchByDistrict) { targetDistrict = Singleton<DistrictManager>.instance.GetDistrict(targetBuilding.Position); } // Set target info on service buildings. foreach (ServiceBuildingInfo serviceBuilding in this.serviceBuildings.Values.Where(sb => sb.CanReceive && sb.VehiclesFree > 0)) { serviceBuilding.SetTargetInfo(targetBuilding, ignoreRange); } // Vehicles that failed to find a path. HashSet<ushort> lostVehicles = new HashSet<ushort>(); // Found vehicle that has enough free capacity. ushort foundVehicleId; float foundVehicleDistance; ServiceBuildingInfo foundVehicleBuilding; // Found vehicle with decent free capacity. ushort foundVehicleDecentId; float foundVehicleDecentDistance; // Found vehicle with ok free capacity. ushort foundVehicleOkId; float foundVehicleOkDistance; ServiceBuildingInfo foundVehicleOkBuilding; bool foundVehicleOkCheck; // Found vehicle with any free capacity. ushort foundVehicleLastResortId; float foundVehicleLastResortDistance; ServiceBuildingInfo foundVehicleLastResortBuilding; bool foundVehicleLastResortCheck; // Created new vehicle. bool createdVehicle; // try n times (in case vehicles have problem finding a path to the buidling) for (int tries = 0; tries < 16; tries++) { ////if (Log.LogALot) ////{ //// Log.DevDebug(this, "AssignVehicle", "Try", tries, allowCreateSpares, this.createSpareVehicles); ////} // Found vehicle that has enough free capacity. foundVehicleId = 0; foundVehicleDistance = float.PositiveInfinity; foundVehicleBuilding = null; // Found vehicle with decent free capacity. foundVehicleDecentId = 0; foundVehicleDecentDistance = float.PositiveInfinity; // Found vehicle with ok free capacity. foundVehicleOkId = 0; foundVehicleOkDistance = float.PositiveInfinity; foundVehicleOkBuilding = null; // Found vehicle with any free capacity. foundVehicleLastResortId = 0; foundVehicleLastResortDistance = float.PositiveInfinity; foundVehicleLastResortBuilding = null; // Created new vehicle. createdVehicle = false; // Loop through service buildings in priority order and assign a vehicle to the target. ////if (Log.LogALot) ////{ //// foreach (ServiceBuildingInfo serviceBuilding in this.serviceBuildings.Values) //// { //// Log.DevDebug(this, "AssignVehicle", "ServiceBuilding?", serviceBuilding.BuildingId, serviceBuilding.CanReceive, serviceBuilding.VehiclesFree, serviceBuilding.VehiclesSpare, serviceBuilding.InRange, serviceBuilding.BuildingName, serviceBuilding.DistrictName); //// } ////} foreach (ServiceBuildingInfo serviceBuilding in this.serviceBuildings.Values.Where(sb => sb.CanReceive && (sb.VehiclesFree > 0 || (allowCreateSpares && this.serviceSettings.CreateSpares != ServiceDispatcherSettings.SpareVehiclesCreation.Never && sb.VehiclesSpare > 0)) && sb.InRange).OrderBy(sb => sb, Global.ServiceBuildingInfoPriorityComparer)) { // Found vehicle that has enough free capacity. foundVehicleId = 0; foundVehicleDistance = float.PositiveInfinity; // Found vehicle with decent free capacity. foundVehicleDecentId = 0; foundVehicleDecentDistance = float.PositiveInfinity; // Whether to check for vehicles with not so decent free capacity. foundVehicleOkCheck = foundVehicleOkId == 0; foundVehicleLastResortCheck = foundVehicleLastResortId == 0; // If prefer to send new vehicle when building is closer. if (allowCreateSpares && this.serviceSettings.CreateSpares == ServiceDispatcherSettings.SpareVehiclesCreation.WhenBuildingIsCloser && serviceBuilding.VehiclesSpare > 0) { foundVehicleDistance = serviceBuilding.Distance; } if (Log.LogALot) { Log.DevDebug(this, "AssignVehicle", "ServiceBuilding", serviceBuilding.BuildingId, serviceBuilding.BuildingName, serviceBuilding.DistrictName, serviceBuilding.Distance, foundVehicleDistance); } // Loop through vehicles and save the closest free vehicle. foreach (ServiceVehicleInfo vehicleInfo in serviceBuilding.Vehicles.Values.Where(vi => vi.FreeToCollect)) { // Don't re-check vehicles that just failed to find path. if (lostVehicles.Contains(vehicleInfo.VehicleId)) { continue; } if (vehicleInfo.IsConfused) { lostVehicles.Add(vehicleInfo.VehicleId); continue; } float distance = (targetBuilding.Position - vehicleInfo.Position).sqrMagnitude; ////if (Log.LogALot) ////{ //// Log.DevDebug(this, "AssignVehicle", "ServiceVehicle", vehicleInfo.VehicleId, vehicleInfo.VehicleName, vehicleInfo.DistrictName, distance); ////} // Check for vehicle with enough free capacity. if ((distance < foundVehicleDistance || (foundVehicleId == 0 && distance == foundVehicleDistance)) && vehicleInfo.CapacityFree >= targetBuilding.ProblemSize) { if (Log.LogALot) { Log.DevDebug(this, "AssignVehicle", "Found", vehicleInfo.VehicleId, distance); } foundVehicleId = vehicleInfo.VehicleId; foundVehicleDistance = distance; } // Check for vehicle with decent free capacity. if (distance < foundVehicleDecentDistance && (vehicleInfo.CapacityUsed < CapacityUsedDecent || (float)vehicleInfo.CapacityFree >= (float)targetBuilding.ProblemSize * CapacityProportionDecent)) { if (Log.LogALot) { Log.DevDebug(this, "AssignVehicle", "FoundDecent", vehicleInfo.VehicleId, distance); } foundVehicleDecentId = vehicleInfo.VehicleId; foundVehicleDecentDistance = distance; } // Check for vehicle with ok free capacity. if (foundVehicleOkCheck && distance < foundVehicleOkDistance && (vehicleInfo.CapacityUsed < CapacityUsedOk || (float)vehicleInfo.CapacityFree >= (float)targetBuilding.ProblemSize * CapacityProportionOk)) { if (Log.LogALot) { Log.DevDebug(this, "AssignVehicle", "FoundOk", vehicleInfo.VehicleId, distance); } foundVehicleOkId = vehicleInfo.VehicleId; foundVehicleOkDistance = distance; foundVehicleOkBuilding = serviceBuilding; } // Check for vehicle with any free capacity. if (foundVehicleLastResortCheck && distance < foundVehicleLastResortDistance && vehicleInfo.CapacityFree > 0) { if (Log.LogALot) { Log.DevDebug(this, "AssignVehicle", "FoundLastResort", vehicleInfo.VehicleId, distance); } foundVehicleLastResortId = vehicleInfo.VehicleId; foundVehicleLastResortDistance = distance; foundVehicleLastResortBuilding = serviceBuilding; } } // If no vehicle with enough free capacity (including the spare vehicles in the building), use the closest with decent free capacity instead. if (foundVehicleDistance == float.PositiveInfinity && foundVehicleDecentDistance < float.PositiveInfinity) { foundVehicleId = foundVehicleDecentId; foundVehicleDistance = foundVehicleDecentDistance; Log.Debug(this, "AssignVehicle", "UsingDecent", targetBuilding.BuildingId, serviceBuilding.BuildingId, serviceBuilding.VehiclesSpare, foundVehicleId, foundVehicleDistance); } // No free vehicle found, but building has spare vehicles so we send one of those. if (foundVehicleId == 0 && allowCreateSpares && !lostVehicles.Contains(0) && this.serviceSettings.CreateSpares != ServiceDispatcherSettings.SpareVehiclesCreation.Never && serviceBuilding.VehiclesSpare > 0) { Log.Debug(this, "AssignVehicle", "CreateSpare", targetBuilding.BuildingId, serviceBuilding.BuildingId, serviceBuilding.VehiclesSpare); lostVehicles.Add(0); foundVehicleId = serviceBuilding.CreateVehicle(this.TransferType, targetBuilding.BuildingId); if (foundVehicleId == 0) { Log.Debug(this, "AssignVehicle", "SpareNotCreated", targetBuilding.BuildingId, serviceBuilding.BuildingId); } else { createdVehicle = true; foundVehicleDistance = serviceBuilding.Distance; if (Log.LogALot) { Vehicle[] vehicles = Singleton<VehicleManager>.instance.m_vehicles.m_buffer; Log.DevDebug( this, "AssignVehicle", "Assign", "C", targetBuilding.BuildingId, serviceBuilding.BuildingId, foundVehicleId, serviceBuilding.VehiclesSpare, serviceBuilding.VehiclesFree, serviceBuilding.VehiclesTotal, targetBuilding.BuildingName, targetBuilding.DistrictName, serviceBuilding.BuildingName, serviceBuilding.DistrictName, VehicleHelper.GetVehicleName(foundVehicleId), vehicles[foundVehicleId].m_targetBuilding, vehicles[foundVehicleId].m_flags); } } } if (foundVehicleId != 0) { foundVehicleBuilding = serviceBuilding; break; } } if (!createdVehicle) { // If no vehicle with decent free capacity (including the spare vehicles in the buildings), use the closest with ok free capacity instead. if (foundVehicleDistance == float.PositiveInfinity && foundVehicleOkDistance < float.PositiveInfinity) { foundVehicleId = foundVehicleDecentId; foundVehicleDistance = foundVehicleDecentDistance; foundVehicleBuilding = foundVehicleOkBuilding; Log.Debug(this, "AssignVehicle", "UsingOk", targetBuilding.BuildingId, foundVehicleBuilding.BuildingId, foundVehicleBuilding.VehiclesSpare, foundVehicleId, foundVehicleDistance); } // If no vehicle with ok free capacity (including the spare vehicles in the buildings), use the closest with any free capacity instead. if (foundVehicleDistance == float.PositiveInfinity && foundVehicleLastResortDistance < float.PositiveInfinity) { foundVehicleId = foundVehicleLastResortId; foundVehicleDistance = foundVehicleLastResortDistance; foundVehicleBuilding = foundVehicleLastResortBuilding; Log.Debug(this, "AssignVehicle", "UsingLastResort", targetBuilding.BuildingId, foundVehicleBuilding.BuildingId, foundVehicleBuilding.VehiclesSpare, foundVehicleId, foundVehicleDistance); } // No free vehicle was found, return. if (foundVehicleId == 0) { if (Log.LogALot) { Log.DevDebug(this, "AssignVehicle", "NotFound"); } return false; } // A free vehicle was found, assign it to the target. { Vehicle[] vehicles = Singleton<VehicleManager>.instance.m_vehicles.m_buffer; if (!foundVehicleBuilding.Vehicles[foundVehicleId].SetTarget(targetBuilding.BuildingId, ref vehicles[foundVehicleId], (TransferManager.TransferReason)this.TransferType)) { // The vehicle failed to find a path to the target. Log.Debug("AssignVehicle", "SetTarget", "Failed", targetBuilding.BuildingId, foundVehicleBuilding.BuildingId, foundVehicleBuilding.VehiclesSpare, foundVehicleId, foundVehicleDistance, vehicles[foundVehicleId].m_flags); lostVehicles.Add(foundVehicleId); continue; } } this.freeVehicles--; foundVehicleBuilding.VehiclesFree--; } targetBuilding.Handled = true; this.assignedTargets[targetBuilding.BuildingId] = Global.CurrentFrame; if (Log.LogToFile) { if (Log.LogALot) { Vehicle[] vehicles = Singleton<VehicleManager>.instance.m_vehicles.m_buffer; Log.DevDebug( this, "AssignVehicle", "Assign", "T", targetBuilding.BuildingId, foundVehicleBuilding.BuildingId, foundVehicleId, targetBuilding.District, targetBuilding.HasProblem, targetBuilding.ProblemValue, targetBuilding.ProblemSize, targetBuilding.BuildingName, targetBuilding.DistrictName, targetBuilding.HasProblem ? "HasProblem" : (string)null, targetBuilding.ProblemValue >= ProblemLimit ? "ProblemLimit" : (string)null, targetBuilding.ProblemValue >= ProblemLimitMajor ? "ProblemLimitMajor" : (string)null, targetBuilding.ProblemValue >= ProblemLimitForgotten ? "ProblemLimitForgotten" : (string)null); Log.DevDebug( this, "AssignVehicle", "Assign", "S", targetBuilding.BuildingId, foundVehicleBuilding.BuildingId, foundVehicleId, foundVehicleBuilding.District, foundVehicleBuilding.InDistrict, foundVehicleBuilding.InRange, foundVehicleBuilding.Range, foundVehicleBuilding.Distance, foundVehicleBuilding.VehiclesTotal, foundVehicleBuilding.VehiclesMade, foundVehicleBuilding.VehiclesFree, foundVehicleBuilding.VehiclesSpare, foundVehicleBuilding.BuildingName, foundVehicleBuilding.DistrictName, foundVehicleBuilding.InDistrict ? "InDistrict" : (string)null, foundVehicleBuilding.InRange ? "InRange" : "OutOfRange"); Log.DevDebug( this, "AssignVehicle", "Assign", "V", targetBuilding.BuildingId, foundVehicleBuilding.BuildingId, foundVehicleId, foundVehicleDistance, foundVehicleBuilding.Vehicles[foundVehicleId].CapacityUsed, foundVehicleBuilding.Vehicles[foundVehicleId].CapacityFree, VehicleHelper.GetVehicleName(foundVehicleId), VehicleHelper.GetDistrictName(foundVehicleId), vehicles[foundVehicleId].m_targetBuilding, vehicles[foundVehicleId].m_flags); } else if (Log.LogNames) { Log.DevDebug( this, "AssignVehicle", "Assign", targetBuilding.BuildingId, foundVehicleBuilding.BuildingId, foundVehicleId, targetBuilding.HasProblem, targetBuilding.ProblemValue, foundVehicleBuilding.InDistrict, foundVehicleBuilding.InRange, foundVehicleBuilding.Range, foundVehicleBuilding.Distance, foundVehicleBuilding.Distance, targetBuilding.BuildingName, targetBuilding.DistrictName, foundVehicleBuilding.BuildingName, foundVehicleBuilding.DistrictName, VehicleHelper.GetVehicleName(foundVehicleId)); } else { Log.Debug( this, "AssignVehicle", "Assign", targetBuilding.BuildingId, foundVehicleBuilding.BuildingId, foundVehicleId, targetBuilding.HasProblem, targetBuilding.ProblemValue, foundVehicleBuilding.InDistrict, foundVehicleBuilding.InRange, foundVehicleBuilding.Range, foundVehicleBuilding.Distance, foundVehicleDistance); } } return true; } return false; }
/// <summary> /// Logs building info for debug use. /// </summary> /// <param name="buildings">The buildings.</param> /// <param name="vehicles">The vehicles.</param> /// <param name="districtManager">The district manager.</param> /// <param name="citizenManager">The citizen manager.</param> /// <param name="buildingId">The building identifier.</param> /// <param name="serviceBuilding">The service building.</param> /// <param name="targetBuilding">The target building.</param> /// <param name="buildingStamp">The building stamp.</param> private static void DebugListLog( Building[] buildings, Vehicle[] vehicles, DistrictManager districtManager, CitizenManager citizenManager, ushort buildingId, ServiceBuildingInfo serviceBuilding, TargetBuildingInfo targetBuilding, BuildingStamp buildingStamp) { if (buildings[buildingId].Info != null && (buildings[buildingId].m_flags & Building.Flags.Created) == Building.Flags.Created) { Log.InfoList info = DebugInfoMsg(buildings, vehicles, districtManager, citizenManager, buildingId, serviceBuilding, targetBuilding, buildingStamp); Log.DevDebug(typeof(BuildingHelper), "DebugListLog", info.ToString()); } }
/// <summary> /// Check whether this building should be checked. /// </summary> /// <param name="building">The building.</param> /// <returns> /// True if the building should be checked. /// </returns> public bool CheckThis(TargetBuildingInfo building) { return building.CheckThis && !building.HandledNow && (building.NeedsService || (this.IncludeUneedy && building.WantsService)) && building.ProblemValue >= this.MinProblemValue && (building.HasProblem || !this.OnlyProblematic); }
/// <summary> /// Collects building info for debug use. /// </summary> /// <param name="buildings">The buildings.</param> /// <param name="vehicles">The vehicles.</param> /// <param name="districtManager">The district manager.</param> /// <param name="citizenManager">The citizen manager.</param> /// <param name="buildingId">The building identifier.</param> /// <param name="serviceBuilding">The service building.</param> /// <param name="targetBuilding">The target building.</param> /// <param name="buildingStamp">The building stamp.</param> /// <param name="verbose">If set to <c>true</c> include more information.</param> /// <returns>The debug information.</returns> private static Log.InfoList DebugInfoMsg( Building[] buildings, Vehicle[] vehicles, DistrictManager districtManager, CitizenManager citizenManager, ushort buildingId, ServiceBuildingInfo serviceBuilding, TargetBuildingInfo targetBuilding, BuildingStamp buildingStamp, bool verbose = false) { Log.InfoList info = new Log.InfoList(); if (buildingStamp != null) { info.Add("O", "BuildingStamp"); } if (serviceBuilding != null) { info.Add("O", "ServiceBuilding"); } if (targetBuilding != null) { info.Add("O", "TargetBuilding"); } List<TargetBuildingInfo> targetBuildings = null; List<ServiceBuildingInfo> serviceBuildings = null; if (verbose && Global.Buildings != null) { targetBuildings = new List<TargetBuildingInfo>(); serviceBuildings = new List<ServiceBuildingInfo>(); if (serviceBuilding == null) { if (Global.Buildings.GarbageBuildings == null || !Global.Buildings.GarbageBuildings.TryGetValue(buildingId, out serviceBuilding)) { serviceBuildings.Add(serviceBuilding); } if (Global.Buildings.DeathCareBuildings == null || !Global.Buildings.DeathCareBuildings.TryGetValue(buildingId, out serviceBuilding)) { serviceBuildings.Add(serviceBuilding); } if (Global.Buildings.HealthCareBuildings == null || !Global.Buildings.HealthCareBuildings.TryGetValue(buildingId, out serviceBuilding)) { serviceBuildings.Add(serviceBuilding); } } if (targetBuilding == null) { if (Global.Buildings.DeadPeopleBuildings == null || !Global.Buildings.DeadPeopleBuildings.TryGetValue(buildingId, out targetBuilding)) { targetBuildings.Add(targetBuilding); } if (Global.Buildings.DirtyBuildings == null || !Global.Buildings.DirtyBuildings.TryGetValue(buildingId, out targetBuilding)) { targetBuildings.Add(targetBuilding); } if (Global.Buildings.SickPeopleBuildings == null || !Global.Buildings.SickPeopleBuildings.TryGetValue(buildingId, out targetBuilding)) { targetBuildings.Add(targetBuilding); } } } info.Add("BuildingId", buildingId); info.Add("AI", buildings[buildingId].Info.m_buildingAI.GetType()); info.Add("InfoName", buildings[buildingId].Info.name); string name = GetBuildingName(buildingId); if (!String.IsNullOrEmpty(name) && name != buildings[buildingId].Info.name) { info.Add("BuildingName", name); } byte district = districtManager.GetDistrict(buildings[buildingId].m_position); info.Add("District", district); info.Add("DistrictName", districtManager.GetDistrictName(district)); if (buildingStamp != null) { info.Add("Source", buildingStamp.Source); info.Add("SimulationTimeStamp", buildingStamp.SimulationTimeStamp); info.Add("SimulationTimeDelta", buildingStamp.SimulationTimeDelta); } if (serviceBuilding != null) { info.Add("CanReceive", serviceBuilding.CanReceive); info.Add("CapacityLevel", serviceBuilding.CapacityLevel); info.Add("CapactyFree", serviceBuilding.CapacityFree); info.Add("CapactyMax", serviceBuilding.CapacityMax); info.Add("CapactyOverflow", serviceBuilding.CapacityOverflow); info.Add("Range", serviceBuilding.Range); info.Add("VehiclesFree", serviceBuilding.VehiclesFree); info.Add("VehiclesSpare", serviceBuilding.VehiclesSpare); info.Add("VehiclesMade", serviceBuilding.VehiclesMade); info.Add("VehiclesTotal", serviceBuilding.VehiclesTotal); } if (serviceBuildings != null) { for (int i = 0; i < serviceBuildings.Count; i++) { serviceBuilding = serviceBuildings[i]; string n = (i + 1).ToString(); info.Add("CanReceive" + n, serviceBuilding.CanReceive); info.Add("CapacityLevel" + n, serviceBuilding.CapacityLevel); info.Add("CapactyFree" + n, serviceBuilding.CapacityFree); info.Add("CapactyMax" + n, serviceBuilding.CapacityMax); info.Add("CapactyOverflow" + n, serviceBuilding.CapacityOverflow); info.Add("Range" + n, serviceBuilding.Range); info.Add("VehiclesFree" + n, serviceBuilding.VehiclesFree); info.Add("VehiclesSpare" + n, serviceBuilding.VehiclesSpare); info.Add("VehiclesMade" + n, serviceBuilding.VehiclesMade); info.Add("VehiclesTotal" + n, serviceBuilding.VehiclesTotal); } } if (targetBuilding != null) { info.Add("Demand", targetBuilding.Demand); info.Add("HasProblem", targetBuilding.HasProblem); info.Add("ProblemSize", targetBuilding.ProblemSize); info.Add("ProblemValue", targetBuilding.ProblemValue); } if (targetBuildings != null) { for (int i = 0; i < targetBuildings.Count; i++) { targetBuilding = targetBuildings[i]; string n = (i + 1).ToString(); info.Add("Demand" + n, targetBuilding.Demand); info.Add("HasProblem" + n, targetBuilding.HasProblem); info.Add("ProblemSize" + n, targetBuilding.ProblemSize); info.Add("ProblemValue" + n, targetBuilding.ProblemValue); } } if (verbose && Global.Buildings != null) { Double desolate; if (Global.Buildings.DesolateBuildings != null && Global.Buildings.DesolateBuildings.TryGetValue(buildingId, out desolate)) { info.Add("Desolate", desolate); } } int materialMax = 0; int materialAmount = 0; int serviceVehicleCount = 0; if (buildings[buildingId].Info.m_buildingAI is CemeteryAI) { serviceVehicleCount = ((CemeteryAI)buildings[buildingId].Info.m_buildingAI).m_hearseCount; info.Add("CorpseCapacity", ((CemeteryAI)buildings[buildingId].Info.m_buildingAI).m_corpseCapacity); info.Add("GraveCount", ((CemeteryAI)buildings[buildingId].Info.m_buildingAI).m_graveCount); info.Add("CustomBuffer1", buildings[buildingId].m_customBuffer1); // GraveCapacity? info.Add("CustomBuffer2", buildings[buildingId].m_customBuffer2); info.Add("PR_HC_Calc", ((buildings[buildingId].m_productionRate * ((CemeteryAI)buildings[buildingId].Info.m_buildingAI).m_hearseCount) + 99) / 100); // Hearse capacity? buildings[buildingId].Info.m_buildingAI.GetMaterialAmount(buildingId, ref buildings[buildingId], TransferManager.TransferReason.Dead, out materialAmount, out materialMax); } else if (buildings[buildingId].Info.m_buildingAI is LandfillSiteAI) { serviceVehicleCount = ((LandfillSiteAI)buildings[buildingId].Info.m_buildingAI).m_garbageTruckCount; buildings[buildingId].Info.m_buildingAI.GetMaterialAmount(buildingId, ref buildings[buildingId], TransferManager.TransferReason.Garbage, out materialAmount, out materialMax); } else if (buildings[buildingId].Info.m_buildingAI is HospitalAI) { serviceVehicleCount = ((HospitalAI)buildings[buildingId].Info.m_buildingAI).m_ambulanceCount; info.Add("", ((HospitalAI)buildings[buildingId].Info.m_buildingAI).m_patientCapacity); buildings[buildingId].Info.m_buildingAI.GetMaterialAmount(buildingId, ref buildings[buildingId], TransferManager.TransferReason.Sick, out materialAmount, out materialMax); } info.Add("materialMax", materialMax); info.Add("materialAmount", materialAmount); info.Add("materialFree", materialMax - materialAmount); int productionRate = buildings[buildingId].m_productionRate; ushort ownVehicleCount = 0; ushort madeVehicleCount = 0; ushort vehicleId = buildings[buildingId].m_ownVehicles; while (vehicleId != 0 && ownVehicleCount < ushort.MaxValue) { ownVehicleCount++; if ((vehicles[vehicleId].m_transferType == (byte)TransferManager.TransferReason.Garbage || vehicles[vehicleId].m_transferType == (byte)TransferManager.TransferReason.Dead) && vehicles[vehicleId].Info != null && (vehicles[vehicleId].m_flags & Vehicle.Flags.Created) == Vehicle.Flags.Created && (vehicles[vehicleId].m_flags & VehicleHelper.VehicleExists) != ~Vehicle.Flags.All) { madeVehicleCount++; } vehicleId = vehicles[vehicleId].m_nextOwnVehicle; } info.Add("OwnVehicles", ownVehicleCount); info.Add("MadeVehicles", madeVehicleCount); info.Add("VehicleCount", serviceVehicleCount); info.Add("ProductionRate", productionRate); info.Add("VehicleCountNominal", ((productionRate * serviceVehicleCount) + 99) / 100); int budget = Singleton<EconomyManager>.instance.GetBudget(buildings[buildingId].Info.m_buildingAI.m_info.m_class); productionRate = PlayerBuildingAI.GetProductionRate(100, budget); int actualVehicleCount = ((productionRate * serviceVehicleCount) + 99) / 100; info.Add("Budget", budget); info.Add("ProductionRateActual", productionRate); info.Add("VehicleCountActual", actualVehicleCount); info.Add("SpareVehicles", actualVehicleCount - ownVehicleCount); float range = buildings[buildingId].Info.m_buildingAI.GetCurrentRange(buildingId, ref buildings[buildingId]); range = range * range * Global.Settings.RangeModifier; if (range < Global.Settings.RangeMinimum) { info.Add("Range", range, Global.Settings.RangeMinimum); } else if (range > Global.Settings.RangeMaximum) { info.Add("Range", range, Global.Settings.RangeMaximum); } else { info.Add("Range", range); } List<string> needs = new List<string>(); if (buildings[buildingId].m_garbageBuffer >= Global.Settings.Garbage.MinimumAmountForDispatch) { needs.Add("Filthy"); } if (buildings[buildingId].m_garbageBuffer >= Global.Settings.Garbage.MinimumAmountForPatrol) { needs.Add("Dirty"); } else if (buildings[buildingId].m_garbageBuffer > 0) { needs.Add("Dusty"); } if (buildings[buildingId].m_deathProblemTimer > 0) { needs.Add("Dead"); } if (buildings[buildingId].m_garbageBuffer * Dispatcher.ProblemBufferModifier >= Dispatcher.ProblemLimitForgotten || buildings[buildingId].m_deathProblemTimer * Dispatcher.ProblemTimerModifier >= Dispatcher.ProblemLimitForgotten) { needs.Add("Forgotten"); } info.Add("Needs", needs); info.Add("DeathProblemTimer", buildings[buildingId].m_deathProblemTimer); info.Add("HealthProblemTimer", buildings[buildingId].m_healthProblemTimer); info.Add("MajorProblemTimer", buildings[buildingId].m_majorProblemTimer); int citizens = 0; int count = 0; uint unitId = buildings[buildingId].m_citizenUnits; while (unitId != 0) { CitizenUnit unit = citizenManager.m_units.m_buffer[unitId]; for (int i = 0; i < 5; i++) { uint citizenId = unit.GetCitizen(i); if (citizenId != 0) { Citizen citizen = citizenManager.m_citizens.m_buffer[citizenId]; if (citizen.Dead && citizen.GetBuildingByLocation() == buildingId) { citizens++; } } } count++; if (count > (int)ushort.MaxValue * 10) { break; } unitId = unit.m_nextUnit; } info.Add("DeadCitizens", citizens); info.Add("GarbageAmount", buildings[buildingId].Info.m_buildingAI.GetGarbageAmount(buildingId, ref buildings[buildingId])); info.Add("GarbageBuffer", buildings[buildingId].m_garbageBuffer); string problems = buildings[buildingId].m_problems.ToString(); if (problems.IndexOfAny(new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }) >= 0) { foreach (Notification.Problem problem in Enum.GetValues(typeof(Notification.Problem))) { if (problem != Notification.Problem.None && (buildings[buildingId].m_problems & problem) == problem) { problems += ", " + problem.ToString(); } } } info.Add("Problems", problems); string flags = buildings[buildingId].m_flags.ToString(); if (flags.IndexOfAny(new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }) >= 0) { foreach (Building.Flags flag in Enum.GetValues(typeof(Building.Flags))) { if (flag != Building.Flags.None && (buildings[buildingId].m_flags & flag) == flag) { flags += ", " + flag.ToString(); } } } info.Add("Flags", flags); string status = buildings[buildingId].Info.m_buildingAI.GetLocalizedStatus(buildingId, ref buildings[buildingId]); if (!String.IsNullOrEmpty(status)) { info.Add("Status", status); } info.Add("AI", buildings[buildingId].Info.m_buildingAI.GetType().AssemblyQualifiedName); return info; }