/// <summary> /// Returns a descriptive text indicating the supply chain destination buildings that the given building /// will ship to. /// </summary> /// <param name="building"></param> /// <returns></returns> public static string GetSupplyBuildingDestinationsText(ushort building) { if (building == 0) { return(string.Empty); } var txtItems = new List <string>(); txtItems.Add($"<<Supply Chain Shipments To>>"); if (Constraints.OutputAllLocalAreas(building)) { txtItems.Add($"All local areas"); } if (Constraints.OutputOutsideConnections(building)) { txtItems.Add($"All outside connections"); } if (Constraints.OutputAllLocalAreas(building)) { return(string.Join("\n", txtItems.ToArray())); } // Next, list output building names var supply = Constraints.SupplyDestinations(building); if (supply?.Count > 0) { var buildingNames = supply .Select(b => $"{GetBuildingName(b)} ({b})") .OrderBy(s => s); foreach (var buildingName in buildingNames) { txtItems.Add(buildingName); } } var districts = Constraints.OutputDistrictParkServiced(building); if (districts?.Count > 0) { // Then add district names var districtParkNames = districts .Select(dp => dp.Name) .OrderBy(s => s); foreach (var districtParkName in districtParkNames) { txtItems.Add($"{districtParkName} (DISTRICT)"); } } if (txtItems.Count == 1) { return($"<<WARNING: No supply chain shipments output!>>"); } else { return(string.Join("\n", txtItems.ToArray())); } }
/// <summary> /// Returns a descriptive text describing problems with this supply chain building ... /// </summary> /// <param name="building"></param> /// <returns></returns> public static string GetSupplyBuildingProblemsText(ushort building) { if (building == 0 || !TransferManagerInfo.IsSupplyChainBuilding(building)) { return(string.Empty); } bool FindSourceBuilding(TransferManager.TransferReason material) { if (material == TransferManager.TransferReason.None) { return(true); } // Assume for now that the outside connection can supply the building with the materials it needs. if (Constraints.InputOutsideConnections(building)) { return(true); } for (ushort buildingIn = 1; buildingIn < BuildingManager.MAX_BUILDING_COUNT; buildingIn++) { if (!TransferManagerInfo.IsSupplyChainBuilding(building)) { continue; } if (GetSupplyBuildingOutputMaterial(buildingIn) == material) { // Check if a supply link exists ... if (Constraints.SupplyDestinations(buildingIn)?.Count > 0 && Constraints.SupplyDestinations(buildingIn).Contains(building)) { return(true); } var requestDistrictPark = TransferManagerInfo.GetDistrictPark(building); var responseDistrictPark = TransferManagerInfo.GetDistrictPark(buildingIn); if (!Constraints.InputAllLocalAreas(building)) { var requestDistrictParksServed = Constraints.InputDistrictParkServiced(building); if (!responseDistrictPark.IsServedBy(requestDistrictParksServed)) { continue; } } if (Constraints.OutputAllLocalAreas(buildingIn)) { return(true); } else { // The call to TransferManagerInfo.GetDistrict applies to offers that are come from buildings, service // vehicles, citizens, AND segments. The latter needs to be considered for road maintenance. var responseDistrictParksServed = Constraints.OutputDistrictParkServiced(buildingIn); if (requestDistrictPark.IsServedBy(responseDistrictParksServed)) { return(true); } } } } return(false); } // Detect if we do have an other building that can supply materials to this building. List <TransferManager.TransferReason> notFound = new List <TransferManager.TransferReason>(); switch (BuildingManager.instance.m_buildings.m_buffer[building].Info?.GetAI()) { case ProcessingFacilityAI processingFacilityAI: if (!FindSourceBuilding(processingFacilityAI.m_inputResource1)) { notFound.Add(processingFacilityAI.m_inputResource1); } if (!FindSourceBuilding(processingFacilityAI.m_inputResource2)) { notFound.Add(processingFacilityAI.m_inputResource2); } if (!FindSourceBuilding(processingFacilityAI.m_inputResource3)) { notFound.Add(processingFacilityAI.m_inputResource3); } if (!FindSourceBuilding(processingFacilityAI.m_inputResource4)) { notFound.Add(processingFacilityAI.m_inputResource4); } break; default: break; } if (notFound.Count > 0) { return(string.Join(",", notFound.Select(x => x.ToString()).ToArray())); } else { return(string.Empty); } }
/// <summary> /// Returns true if we can potentially match the two given offers. /// </summary> /// <returns></returns> private static bool IsValidSupplyChainOffer( TransferManager.TransferReason material, ref TransferManager.TransferOffer requestOffer, int requestPriority, ref TransferManager.TransferOffer responseOffer, int responsePriority) { var requestBuilding = TransferManagerInfo.GetHomeBuilding(ref requestOffer); var responseBuilding = TransferManagerInfo.GetHomeBuilding(ref responseOffer); if (responseBuilding == 0) { Logger.LogMaterial( $"TransferManager::IsValidSupplyChainOffer: {Utils.ToString(ref responseOffer, material)}, not a district services building", material); return(false); } // First check if a supply link exists. var responseSupplyDestinations = Constraints.SupplyDestinations(responseBuilding); if (responseSupplyDestinations?.Count > 0) { for (int i = 0; i < responseSupplyDestinations.Count; i++) { if (responseSupplyDestinations[i] == (int)requestBuilding) { Logger.LogMaterial( $"TransferManager::IsValidSupplyChainOffer: {Utils.ToString(ref responseOffer, material)}, supply link allowed", material); return(true); } } } // Special logic if both buildings are warehouses. Used to prevent goods from being shuffled back and forth between warehouses. if (BuildingManager.instance.m_buildings.m_buffer[requestBuilding].Info.GetAI() is WarehouseAI && BuildingManager.instance.m_buildings.m_buffer[responseBuilding].Info.GetAI() is WarehouseAI) { return(false); } // Now match on all local areas and district restrictions, both on request an response buildings! var requestDistrictPark = TransferManagerInfo.GetDistrictPark(material, ref requestOffer); var responseDistrictPark = TransferManagerInfo.GetDistrictPark(material, ref responseOffer); // If the request constrains the districts that it can accept orders from ... if (!Constraints.InputAllLocalAreas(requestBuilding)) { var requestDistrictParksServed = Constraints.InputDistrictParkServiced(requestBuilding); if (!responseDistrictPark.IsServedBy(requestDistrictParksServed)) { Logger.LogMaterial( $"TransferManager::IsValidSupplyChainOffer: {Utils.ToString(ref responseOffer, material)}, request is constrained to accept offers from certain districts only!", material); return(false); } } if (!Constraints.InputOutsideConnections(requestBuilding) && TransferManagerInfo.IsOutsideOffer(ref responseOffer)) { Logger.LogMaterial( $"TransferManager::IsValidSupplyChainOffer: {Utils.ToString(ref responseOffer, material)}, request is constrained not to accept outside offers!", material); return(false); } if (Constraints.OutputAllLocalAreas(responseBuilding)) { Logger.LogMaterial( $"TransferManager::IsValidSupplyChainOffer: {Utils.ToString(ref responseOffer, material)}, serves all local areas", material); return(true); } else { // The call to TransferManagerInfo.GetDistrict applies to offers that are come from buildings, service // vehicles, citizens, AND segments. The latter needs to be considered for road maintenance. var responseDistrictParksServed = Constraints.OutputDistrictParkServiced(responseBuilding); if (requestDistrictPark.IsServedBy(responseDistrictParksServed)) { Logger.LogMaterial( $"TransferManager::IsValidSupplyChainOffer: {Utils.ToString(ref responseOffer, material)}, serves district {requestDistrictPark.Name}", material); return(true); } } Logger.LogMaterial( $"TransferManager::IsValidSupplyChainOffer: {Utils.ToString(ref responseOffer, material)}, not valid", material); return(false); }