diff --git a/src/RealTime/CustomAI/RealTimeBuildingAI.cs b/src/RealTime/CustomAI/RealTimeBuildingAI.cs index 3fe1b5880b147c1a0338c1032261ace13a528cde..ae6e88713c28ae7258ee536d11359a1f92669bc5 100644 --- a/src/RealTime/CustomAI/RealTimeBuildingAI.cs +++ b/src/RealTime/CustomAI/RealTimeBuildingAI.cs @@ -319,6 +319,32 @@ namespace RealTime.CustomAI return true; } + /// + /// Determines whether the building with the specified ID is a shopping target. + /// + /// The building ID to check. + /// + /// true if the building is a shopping target; otherwise, false. + /// + public bool IsShoppingTarget(ushort buildingId) + { + if (buildingId == 0) + { + return true; + } + + // A building still can post outgoing offers while inactive. + // This is to prevent those offers from being dispatched. + if (!buildingManager.BuildingHasFlags(buildingId, Building.Flags.Active)) + { + return false; + } + + var buildingService = buildingManager.GetBuildingService(buildingId); + return buildingService != ItemClass.Service.VarsitySports + && buildingManager.IsRealUniqueBuilding(buildingId); + } + /// Determines whether a building with specified ID is currently active. /// The ID of the building to check. /// diff --git a/src/RealTime/GameConnection/BuildingManagerConnection.cs b/src/RealTime/GameConnection/BuildingManagerConnection.cs index b9cd34ac0240286cacfb0ef647df681c67c3ca16..491042c173f0e92c6c9222a0e616015d2921e95c 100644 --- a/src/RealTime/GameConnection/BuildingManagerConnection.cs +++ b/src/RealTime/GameConnection/BuildingManagerConnection.cs @@ -422,6 +422,32 @@ namespace RealTime.GameConnection public bool IsAreaEvacuating(ushort buildingId) => buildingId != 0 && DisasterManager.instance.IsEvacuating(BuildingManager.instance.m_buildings.m_buffer[buildingId].m_position); + /// + /// Determines whether the building with specified ID is a real unique building (not a stadium, not a concert area). + /// + /// The building ID to check. + /// + /// true if the building with the specified ID is a real unique building; otherwise, false. + /// + [System.Diagnostics.CodeAnalysis.SuppressMessage("General", "RCS1130", Justification = "The EventType enum has no [Flags] attribute but has values of power of 2")] + public bool IsRealUniqueBuilding(ushort buildingId) + { + if (buildingId == 0) + { + return false; + } + + var buildingInfo = BuildingManager.instance.m_buildings.m_buffer[buildingId].Info; + if (buildingInfo?.m_class?.m_service != ItemClass.Service.Monument) + { + return false; + } + + var monumentAI = buildingInfo.m_buildingAI as MonumentAI; + return monumentAI != null + && (monumentAI.m_supportEvents & (EventManager.EventType.Football | EventManager.EventType.Concert)) == 0; + } + private static bool BuildingCanBeVisited(ushort buildingId) { uint currentUnitId = BuildingManager.instance.m_buildings.m_buffer[buildingId].m_citizenUnits; diff --git a/src/RealTime/GameConnection/IBuildingManagerConnection.cs b/src/RealTime/GameConnection/IBuildingManagerConnection.cs index 81e73a665a9180769fa47d3631d8846febff6b2e..baa11dcac4f84a5a5f4697cfc779b9f9ef837e24 100644 --- a/src/RealTime/GameConnection/IBuildingManagerConnection.cs +++ b/src/RealTime/GameConnection/IBuildingManagerConnection.cs @@ -184,8 +184,17 @@ namespace RealTime.GameConnection /// /// The building ID to check. /// - /// true if the area around the building with specified ID is currently being evacuated.; otherwise, false. + /// true if the area around the building with specified ID is currently being evacuated; otherwise, false. /// bool IsAreaEvacuating(ushort buildingId); + + /// + /// Determines whether the building with specified ID is a real unique building (not a stadium, not a concert area). + /// + /// The building ID to check. + /// + /// true if the building with the specified ID is a real unique building; otherwise, false. + /// + bool IsRealUniqueBuilding(ushort buildingId); } } \ No newline at end of file diff --git a/src/RealTime/GameConnection/Patches/TransferManagerPatch.cs b/src/RealTime/GameConnection/Patches/TransferManagerPatch.cs index 8e91d9c0eebcc3c9ddc4929029bc2535474ae9bb..4fb03a902a0d78e411c0c5cdf9c82d876bd272d4 100644 --- a/src/RealTime/GameConnection/Patches/TransferManagerPatch.cs +++ b/src/RealTime/GameConnection/Patches/TransferManagerPatch.cs @@ -46,6 +46,16 @@ namespace RealTime.GameConnection.Patches case TransferManager.TransferReason.TouristD: return RealTimeAI.IsEntertainmentTarget(offer.Building); + case TransferManager.TransferReason.Shopping: + case TransferManager.TransferReason.ShoppingB: + case TransferManager.TransferReason.ShoppingC: + case TransferManager.TransferReason.ShoppingD: + case TransferManager.TransferReason.ShoppingE: + case TransferManager.TransferReason.ShoppingF: + case TransferManager.TransferReason.ShoppingG: + case TransferManager.TransferReason.ShoppingH: + return RealTimeAI.IsShoppingTarget(offer.Building); + case TransferManager.TransferReason.ParkMaintenance: return RealTimeAI.IsBuildingActive(offer.Building);