/// <summary>
        /// Logs the transfer offers.
        /// </summary>
        /// <param name="direction">The direction.</param>
        /// <param name="offers">The offers.</param>
        /// <param name="count">The count.</param>
        /// <param name="amount">The amount.</param>
        /// <param name="buildings">The buildings.</param>
        /// <param name="material">The material.</param>
        private static void DebugListLog(
            string direction,
            TransferManager.TransferOffer[] offers,
            ushort[] count,
            int[] amount,
            Building[] buildings,
            TransferManager.TransferReason material)
        {
            for (int priority = 0; priority < 8; priority++)
            {
                int index = ((int)material * 8) + priority;
                for (int i = 0; i < count[index]; i++)
                {
                    Log.InfoList info = new Log.InfoList();
                    TransferManager.TransferOffer offer = offers[(index * 256) + i];

                    info.Add("Active", offer.Active);
                    info.Add("Amount", offer.Amount);
                    info.Add("Priority", offer.Priority);
                    info.Add("Vehicle", offer.Vehicle, VehicleHelper.GetVehicleName(offer.Vehicle));
                    info.Add("Citizen", offer.Citizen, CitizenHelper.GetCitizenName(offer.Citizen));
                    info.Add("TransportLine", offer.TransportLine, TransportLineHelper.GetLineName(offer.TransportLine));
                    info.Add("Building", offer.Building, BuildingHelper.GetBuildingName(offer.Building), BuildingHelper.GetDistrictName(offer.Building));

                    if (buildings != null && offer.Building > 0 && buildings[offer.Building].Info != null && (buildings[offer.Building].m_flags & Building.Flags.Created) == Building.Flags.Created)
                    {
                        info.Add("Garbage", buildings[offer.Building].m_garbageBuffer);
                        info.Add("Dead", buildings[offer.Building].m_deathProblemTimer);
                    }

                    Log.DevDebug(typeof(TransferManagerHelper), "DebugListLog", direction, material, info);
                }
            }
        }
        /// <summary>
        /// Helper method for adding the given offer to the offers array.
        /// </summary>
        /// <param name="material"></param>
        /// <param name="offer"></param>
        /// <param name="amounts"></param>
        /// <param name="count"></param>
        /// <param name="offers"></param>
        private static void AddOffer(TransferManager.TransferReason material, TransferManager.TransferOffer offer, int[] amount, ushort[] count, TransferManager.TransferOffer[] offers)
        {
            for (int priority = offer.Priority; priority >= 0; --priority)
            {
                int index1 = (int)material * 8 + priority;
                int num    = count[index1];

                for (int index2 = 0; index2 < num; index2++)
                {
                    int index3 = index1 * 256 + index2;
                    if (offers[index3].m_object == offer.m_object)
                    {
                        // Found an existing offer.
                        return;
                    }
                }

                // If we reached here, we need to add a new offer.
                if (num < 256)
                {
                    offers[index1 * 256 + num] = offer;
                    count[index1]          = (ushort)(num + 1);
                    amount[(int)material] += offer.Amount;
                    return;
                }
            }
        }
Example #3
0
        public override void StartTransfer(ushort vehicleID, ref Vehicle data, TransferManager.TransferReason material, TransferManager.TransferOffer offer)
        {
            if ((data.m_flags & Vehicle.Flags.TransferToTarget) != 0)
            {
                base.StartTransfer(vehicleID, ref data, material, offer);
                return;
            }

            Debug.Log("Starting Transfer");
            try
            {
                districtNo[vehicleID] = Singleton <DistrictManager> .instance.GetDistrict(Singleton <BuildingManager> .instance.m_buildings.m_buffer[data.m_sourceBuilding].m_position);

                currentClaim[vehicleID] = DeathRegistry.GetDeathClaim(districtNo[vehicleID], data.GetLastFramePosition());
            } catch (Exception E) { return; }

            if (currentClaim[vehicleID] == null)
            {
                return;
            }

            Debug.Log("Successful!");

            TransferManager.TransferOffer betterOffer = new TransferManager.TransferOffer();

            betterOffer.Active   = true;
            betterOffer.Amount   = 0;
            betterOffer.Building = currentClaim[vehicleID].buildingID;
            betterOffer.Citizen  = currentClaim[vehicleID].citizenID;

            base.StartTransfer(vehicleID, ref data, material, betterOffer);
        }
Example #4
0
        /// <summary>
        /// Helper method for dumping the contents of an offer, for debugging purposes.
        /// </summary>
        /// <param name="offer"></param>
        /// <param name="material"></param>
        /// <returns></returns>
        public static string ToString(ref TransferManager.TransferOffer offer, TransferManager.TransferReason material)
        {
            var outsideOfferText = TransferManagerInfo.IsOutsideOffer(ref offer) ? "(O)" : "";

            if (offer.NetSegment != 0)
            {
                return($"Id=S{offer.NetSegment}, (Amt,Mat,Pri,Exc,Act)=({offer.Amount},{material},{offer.Priority},{offer.Exclude},{offer.Active})");
            }

            if (offer.Vehicle != 0)
            {
                var homeBuilding = VehicleManager.instance.m_vehicles.m_buffer[offer.Vehicle].m_sourceBuilding;
                return($"Id=V{offer.Vehicle}, Home=B{homeBuilding}{outsideOfferText}, (Amt,Mat,Pri,Exc,Act)=({offer.Amount},{material},{offer.Priority},{offer.Exclude},{offer.Active})");
            }

            if (offer.Citizen != 0)
            {
                var homeBuilding = CitizenManager.instance.m_citizens.m_buffer[offer.Citizen].m_homeBuilding;
                return($"Id=C{offer.Citizen}, Home=B{homeBuilding}{outsideOfferText}, (Amt,Mat,Pri,Exc,Act)=({offer.Amount},{material},{offer.Priority},{offer.Exclude},{offer.Active})");
            }

            if (offer.Building != 0)
            {
                return($"Id=B{offer.Building}{outsideOfferText}, (Amt,Mat,Pri,Exc,Act)=({offer.Amount},{material},{offer.Priority},{offer.Exclude},{offer.Active})");
            }

            return($"Id=0, (Amt,Mat,Pri,Exc,Act)=({offer.Amount},{material},{offer.Priority},{offer.Exclude},{offer.Active})");
        }
 public static bool Prefix(ushort vehicleID, ref Vehicle data, TransferManager.TransferReason material,
                           TransferManager.TransferOffer offer)
 {
     Debug.Log("Start Transfer Called");
     Debug.Log("Start Transfer Called");
     return(DistrictHelper.CanTransfer(data.m_sourceBuilding, material, offer));
 }
Example #6
0
            private static bool Prefix(TransferManager.TransferReason material, ref TransferManager.TransferOffer offer)
            {
                switch (material)
                {
                case TransferManager.TransferReason.Entertainment:
                case TransferManager.TransferReason.EntertainmentB:
                case TransferManager.TransferReason.EntertainmentC:
                case TransferManager.TransferReason.EntertainmentD:
                case TransferManager.TransferReason.TouristA:
                case TransferManager.TransferReason.TouristB:
                case TransferManager.TransferReason.TouristC:
                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));

                default:
                    return(true);
                }
            }
        /// <summary>
        /// Point of note: This is a static function whereas the original function uses __thiscall.
        /// On x64 machines only __fastcall is left, which means that the first parameter lives in
        /// RCX - which conveniently conincides with the register usually used for the this-ptr
        /// (at least on Windows).
        /// </summary>
        /// <param name="manager"></param>
        /// <param name="material"></param>
        /// <param name="offer"></param>
        public static void AddIncomingOffer(TransferManager manager, TransferManager.TransferReason material, TransferManager.TransferOffer offer)
        {
            // note: do NOT just use
            //   DebugOutputPanel.AddMessage
            // here. This method is called so frequently that it will actually crash the game.
            if (!_init)
            {
                _init = true;
                Init();
            }
            DebugLog.LogToFileOnly("AddIncomingOffer for " + material + " from " + Environment.StackTrace);

            for (int priority = offer.Priority; priority >= 0; --priority)
            {
                int index = (int)material * 8 + priority;
                int count = _incomingCount[index];
                if (count < 256)
                {
                    _incomingOffers[index * 256 + count] = offer;
                    _incomingCount[index]           = (ushort)(count + 1);
                    _incomingAmount[(int)material] += offer.Amount;
                    break;
                }
            }
        }
Example #8
0
        private static bool StartTransferPre(
            DepotAI __instance,
            ref ushort buildingID, ref Building data,
            TransferManager.TransferReason reason,
            TransferManager.TransferOffer offer)
        {
            var lineID = offer.TransportLine;
            //TODO: fish boats?
            //TODO: also check reason? - see DepotAI
            var info = TransportManager.instance.m_lines.m_buffer[lineID].Info;

            if (lineID <= 0 || info?.m_class == null || info.m_class.m_service == ItemClass.Service.Disaster)
            {
                return(true); //if it's not a proper transport line, let's not modify the behavior
            }

            var depot = CachedTransportLineData._lineData[lineID].Depot;

            if (!DepotUtil.ValidateDepotAndFindNewIfNeeded(lineID, ref depot, info))
            {
                if (depot == 0)
                {
                    Debug.LogWarning($"IPT2: No proper depot was found for line {lineID}!");
                    CachedTransportLineData.ClearEnqueuedVehicles(lineID);
                    return(false);
                }

                Debug.LogWarning($"IPT2: Invalid or no depot was selected for line {lineID}, resetting to : {depot}!");
                CachedTransportLineData.ClearEnqueuedVehicles(lineID);
                return(false);
            }


            if (depot == buildingID)
            {
                if (SimHelper.SimulationTime < CachedTransportLineData.GetNextSpawnTime(lineID))
                {
                    return(false); //if we need to wait before spawn, let's wait
                }

                if (!DepotUtil.CanAddVehicle(depot, ref BuildingManager.instance.m_buildings.m_buffer[depot], info))
                {
                    CachedTransportLineData.ClearEnqueuedVehicles(lineID);
                    return(false);
                }

                CachedTransportLineData.SetNextSpawnTime(lineID, SimHelper.SimulationTime + OptionsWrapper <Settings> .Options.SpawnTimeInterval);
            }
            else
            {
                Debug.Log("IPT2: Redirecting from " + buildingID + " to " + depot);
                __instance.StartTransfer(depot, ref BuildingManager.instance.m_buildings.m_buffer[depot], reason,
                                         offer);
                return(false);
            }

            return(true);
        }
Example #9
0
        public static void ProcessCityResourceDepartmentBuildingOutgoing(ushort buildingID, ref Building buildingData)
        {
            int num27 = 0;
            int num28 = 0;
            int num29 = 0;
            int value = 0;

            TransferManager.TransferReason outgoingTransferReason = default(TransferManager.TransferReason);

            //constructionResource
            System.Random rand = new System.Random();
            outgoingTransferReason = (TransferManager.TransferReason) 124;
            if (outgoingTransferReason != TransferManager.TransferReason.None)
            {
                CaculationVehicle.CustomCalculateOwnVehicles(buildingID, ref buildingData, outgoingTransferReason, ref num27, ref num28, ref num29, ref value);
                buildingData.m_tempExport = (byte)Mathf.Clamp(value, (int)buildingData.m_tempExport, 255);
            }

            if (buildingData.m_fireIntensity == 0 && outgoingTransferReason != TransferManager.TransferReason.None && buildingData.m_flags.IsFlagSet(Building.Flags.Completed))
            {
                int num36        = 20;
                int customBuffer = MainDataStore.constructionResourceBuffer[buildingID];
                if (customBuffer >= 8000 && num27 < num36)
                {
                    TransferManager.TransferOffer offer2 = default(TransferManager.TransferOffer);
                    offer2.Priority = rand.Next(8);
                    offer2.Building = buildingID;
                    offer2.Position = buildingData.m_position;
                    offer2.Amount   = Mathf.Min(customBuffer / 8000, num36 - num27);
                    offer2.Active   = true;
                    Singleton <TransferManager> .instance.AddOutgoingOffer(outgoingTransferReason, offer2);
                }
            }

            //operationResource
            outgoingTransferReason = (TransferManager.TransferReason) 125;
            if (outgoingTransferReason != TransferManager.TransferReason.None)
            {
                CaculationVehicle.CustomCalculateOwnVehicles(buildingID, ref buildingData, outgoingTransferReason, ref num27, ref num28, ref num29, ref value);
                buildingData.m_tempExport = (byte)Mathf.Clamp(value, (int)buildingData.m_tempExport, 255);
            }

            if (buildingData.m_fireIntensity == 0 && outgoingTransferReason != TransferManager.TransferReason.None && buildingData.m_flags.IsFlagSet(Building.Flags.Completed))
            {
                int num36        = 20;
                int customBuffer = MainDataStore.operationResourceBuffer[buildingID];
                if (customBuffer >= 8000 && num27 < num36)
                {
                    TransferManager.TransferOffer offer2 = default(TransferManager.TransferOffer);
                    offer2.Priority = rand.Next(8);
                    offer2.Building = buildingID;
                    offer2.Position = buildingData.m_position;
                    offer2.Amount   = Mathf.Min((customBuffer) / 8000, num36 - num27);
                    offer2.Active   = true;
                    Singleton <TransferManager> .instance.AddOutgoingOffer(outgoingTransferReason, offer2);
                }
            }
        }
 public static void CommonBuildingAIReleaseBuildingPostfix(ushort buildingID)
 {
     MainDataStore.petrolBuffer[buildingID]             = 0;
     MainDataStore.tempVehicleForFuelCount[buildingID]  = 0;
     MainDataStore.finalVehicleForFuelCount[buildingID] = 0;
     TransferManager.TransferOffer offer = default(TransferManager.TransferOffer);
     offer.Building = buildingID;
     Singleton <TransferManager> .instance.RemoveOutgoingOffer((TransferManager.TransferReason) 112, offer);
 }
        public static void FindVisitPlace(uint citizenID, ushort sourceBuilding, TransferManager.TransferReason reason)
        {
            TransferManager.TransferOffer offer = default;
            offer.Priority = Singleton <SimulationManager> .instance.m_randomizer.Int32(7u);

            offer.Citizen  = citizenID;
            offer.Position = Singleton <BuildingManager> .instance.m_buildings.m_buffer[sourceBuilding].m_position;
            offer.Amount   = 1;
            offer.Active   = true;
            Singleton <TransferManager> .instance.AddIncomingOffer(reason, offer);
        }
        public static void Postfix(ushort buildingID)
        {
            MainDataStore.petrolBuffer[buildingID]             = 0;
            MainDataStore.resourceCategory[buildingID]         = 0;
            MainDataStore.finalVehicleForFuelCount[buildingID] = 0;
            TransferManager.TransferOffer offer = default;
            offer.Building = buildingID;
            Singleton <TransferManager> .instance.RemoveOutgoingOffer((TransferManager.TransferReason) 126, offer);

            Singleton <TransferManager> .instance.RemoveOutgoingOffer((TransferManager.TransferReason) 127, offer);
        }
        private static bool IsSameLocation(
            ref TransferManager.TransferOffer requestOffer,
            ref TransferManager.TransferOffer responseOffer)
        {
            if (requestOffer.m_object == responseOffer.m_object)
            {
                return(true);
            }

            var requestHomeBuilding  = TransferManagerInfo.GetHomeBuilding(ref requestOffer);
            var responseHomeBuilding = TransferManagerInfo.GetHomeBuilding(ref responseOffer);

            if (requestHomeBuilding == responseHomeBuilding)
            {
                return(true);
            }

            // Don't match a guest vehicle to its host building.  For instance, Taxi stands.
            if (responseOffer.Vehicle != 0 && BuildingManager.instance.m_buildings.m_buffer[requestHomeBuilding].m_guestVehicles != 0)
            {
                var vehicleID = BuildingManager.instance.m_buildings.m_buffer[requestHomeBuilding].m_guestVehicles;
                int num       = 0;
                while (vehicleID != 0)
                {
                    if (responseOffer.Vehicle == vehicleID)
                    {
                        return(true);
                    }

                    vehicleID = VehicleManager.instance.m_vehicles.m_buffer[vehicleID].m_nextGuestVehicle;
                    ++num;

                    if (++num > 16384)
                    {
                        CODebugBase <LogChannel> .Error(LogChannel.Core, "Invalid list detected!\n" + System.Environment.StackTrace);

                        break;
                    }
                }
            }

            // Don't match outside connections that are too close to each other.
            if (TransferManagerInfo.IsOutsideBuilding(requestHomeBuilding) && TransferManagerInfo.IsOutsideBuilding(responseHomeBuilding))
            {
                var requestPosition  = BuildingManager.instance.m_buildings.m_buffer[requestHomeBuilding].m_position;
                var responsePosition = BuildingManager.instance.m_buildings.m_buffer[responseHomeBuilding].m_position;

                var distanceSquared = Vector3.SqrMagnitude(responsePosition - requestPosition);
                return(distanceSquared <= 100000);
            }

            return(false);
        }
Example #14
0
        public static void ProcessBuildingConstruction(ushort buildingID, ref Building buildingData, ref Building.Frame frameData)
        {
            if (MainDataStore.constructionResourceBuffer[buildingID] < 8000 && (!ResourceBuildingAI.IsSpecialBuilding(buildingID)))
            {
                System.Random rand = new System.Random();
                if (buildingData.m_flags.IsFlagSet(Building.Flags.Created) && (!buildingData.m_flags.IsFlagSet(Building.Flags.Completed)) && (!buildingData.m_flags.IsFlagSet(Building.Flags.Deleted)))
                {
                    frameData.m_constructState = 10;
                    int num27 = 0;
                    int num28 = 0;
                    int num29 = 0;
                    int value = 0;
                    int num34 = 0;
                    TransferManager.TransferReason incomingTransferReason = default(TransferManager.TransferReason);
                    //construction resource
                    incomingTransferReason = (TransferManager.TransferReason) 124;
                    num27 = 0;
                    num28 = 0;
                    num29 = 0;
                    value = 0;
                    num34 = 0;
                    if (incomingTransferReason != TransferManager.TransferReason.None)
                    {
                        CaculationVehicle.CustomCalculateGuestVehicles(buildingID, ref buildingData, incomingTransferReason, ref num27, ref num28, ref num29, ref value);
                        buildingData.m_tempImport = (byte)Mathf.Clamp(value, (int)buildingData.m_tempImport, 255);
                    }

                    num34 = 8000 - MainDataStore.constructionResourceBuffer[buildingID] - num29;
                    if (num34 > 0)
                    {
                        TransferManager.TransferOffer offer = default(TransferManager.TransferOffer);
                        offer.Priority = rand.Next(8);
                        if ((buildingData.Info.m_class.m_service != ItemClass.Service.Residential) && (buildingData.Info.m_class.m_service != ItemClass.Service.Industrial) && (buildingData.Info.m_class.m_service != ItemClass.Service.Commercial) && (buildingData.Info.m_class.m_service != ItemClass.Service.Office))
                        {
                            offer.Priority = 7;
                        }
                        offer.Building = buildingID;
                        offer.Position = buildingData.m_position;
                        offer.Amount   = 1;
                        offer.Active   = false;
                        Singleton <TransferManager> .instance.AddIncomingOffer(incomingTransferReason, offer);
                    }
                }
            }
            else
            {
                if (!ResourceBuildingAI.IsSpecialBuilding(buildingID) && buildingData.m_flags.IsFlagSet(Building.Flags.Completed))
                {
                    MainDataStore.constructionResourceBuffer[buildingID] = 0;
                }
            }
        }
        /// <summary>
        /// Makes an offer.
        /// </summary>
        /// <param name="targetBuildingId">The target building identifier.</param>
        /// <param name="targetCitizenId">The target citizen identifier.</param>
        /// <returns>The offer.</returns>
        public static TransferManager.TransferOffer MakeOffer(ushort targetBuildingId, uint targetCitizenId)
        {
            TransferManager.TransferOffer offer = new TransferManager.TransferOffer();
            if (targetCitizenId == 0)
            {
                offer.Building = targetBuildingId;
            }
            else
            {
                offer.Citizen = targetCitizenId;
            }

            return(offer);
        }
        /// <summary>
        /// Returns true if we can potentially match the two given offers.
        /// </summary>
        /// <returns></returns>
        private static bool IsValidDistrictOffer(
            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::IsValidDistrictOffer: {Utils.ToString(ref responseOffer, material)}, not a district services building",
                    material);
                return(false);
            }

            // 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);
            }

            if (Constraints.OutputAllLocalAreas(responseBuilding))
            {
                Logger.LogMaterial(
                    $"TransferManager::IsValidDistrictOffer: {Utils.ToString(ref responseOffer, material)}, serves all local areas",
                    material);
                return(true);
            }

            // 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 requestDistrictPark         = TransferManagerInfo.GetDistrictPark(material, ref requestOffer);
            var responseDistrictParksServed = Constraints.OutputDistrictParkServiced(responseBuilding);

            if (requestDistrictPark.IsServedBy(responseDistrictParksServed))
            {
                Logger.LogMaterial(
                    $"TransferManager::IsValidDistrictOffer: {Utils.ToString(ref responseOffer, material)}, serves district {requestDistrictPark.Name}",
                    material);
                return(true);
            }

            Logger.LogMaterial(
                $"TransferManager::IsValidDistrictOffer: {Utils.ToString(ref responseOffer, material)}, not valid",
                material);
            return(false);
        }
        public static bool Prefix(ushort buildingID, ref Building data, TransferManager.TransferReason material,
                                  TransferManager.TransferOffer offer)
        {
            if (DistrictHelper.BuildingTransfer(buildingID, material, offer))
            {
                DebugHelper.Log($"Transfer Request Accepted.");
                return(true);
            }

            BuildingHelper.MoveRequest(buildingID, ref data, material, offer);
            {
                DebugHelper.Log("Moving Transfer Request.");
                return(false);
            }
        }
Example #18
0
        public static void Postfix(ushort buildingID, ref Building data)
        {
            MainDataStore.foodBuffer[buildingID]   = 0;
            MainDataStore.lumberBuffer[buildingID] = 0;
            MainDataStore.petrolBuffer[buildingID] = 0;
            MainDataStore.coalBuffer[buildingID]   = 0;
            MainDataStore.constructionResourceBuffer[buildingID] = 0;
            MainDataStore.operationResourceBuffer[buildingID]    = 0;
            MainDataStore.resourceCategory[buildingID]           = 0;
            TransferManager.TransferOffer offer = default(TransferManager.TransferOffer);
            offer.Building = buildingID;
            Singleton <TransferManager> .instance.RemoveOutgoingOffer((TransferManager.TransferReason) 124, offer);

            Singleton <TransferManager> .instance.RemoveOutgoingOffer((TransferManager.TransferReason) 125, offer);
        }
Example #19
0
        public static void ProcessPlayerBuildingOperation(ushort buildingID, ref Building buildingData)
        {
            if (buildingData.m_fireIntensity == 0 && buildingData.m_flags.IsFlagSet(Building.Flags.Completed))
            {
                int num27 = 0;
                int num28 = 0;
                int num29 = 0;
                int value = 0;
                int num34 = 0;
                TransferManager.TransferReason incomingTransferReason = default(TransferManager.TransferReason);
                //operation resource
                incomingTransferReason = (TransferManager.TransferReason) 125;
                num27 = 0;
                num28 = 0;
                num29 = 0;
                value = 0;
                num34 = 0;
                if (incomingTransferReason != TransferManager.TransferReason.None)
                {
                    CaculationVehicle.CustomCalculateGuestVehicles(buildingID, ref buildingData, incomingTransferReason, ref num27, ref num28, ref num29, ref value);
                    buildingData.m_tempImport = (byte)Mathf.Clamp(value, (int)buildingData.m_tempImport, 255);
                }

                num34 = 15000 - MainDataStore.operationResourceBuffer[buildingID] - num29;
                if (num34 > 0)
                {
                    TransferManager.TransferOffer offer = default(TransferManager.TransferOffer);
                    //Higher priority for Electricity and Water sevice.
                    if (buildingData.Info.m_class.m_service == ItemClass.Service.Water || buildingData.Info.m_class.m_service == ItemClass.Service.Electricity || buildingData.Info.m_class.m_service == ItemClass.Service.Garbage)
                    {
                        offer.Priority = num34 / 1000;
                    }
                    else
                    {
                        offer.Priority = num34 / 3000;
                    }
                    if (offer.Priority > 7)
                    {
                        offer.Priority = 7;
                    }
                    offer.Building = buildingID;
                    offer.Position = buildingData.m_position;
                    offer.Amount   = 1;
                    offer.Active   = false;
                    Singleton <TransferManager> .instance.AddIncomingOffer(incomingTransferReason, offer);
                }
            }
        }
Example #20
0
        // TODO: inherit CarAI

        private void RemoveOffers(ushort vehicleID, ref Vehicle data)
        {
            if ((data.m_flags & Vehicle.Flags.WaitingTarget) != Vehicle.Flags.None)
            {
                TransferManager.TransferOffer offer = default(TransferManager.TransferOffer);
                offer.Vehicle = vehicleID;
                if ((data.m_flags & Vehicle.Flags.TransferToSource) != Vehicle.Flags.None)
                {
                    Singleton <TransferManager> .instance.RemoveIncomingOffer((TransferManager.TransferReason) data.m_transferType, offer);
                }
                else if ((data.m_flags & Vehicle.Flags.TransferToTarget) != Vehicle.Flags.None)
                {
                    Singleton <TransferManager> .instance.RemoveOutgoingOffer((TransferManager.TransferReason) data.m_transferType, offer);
                }
            }
        }
        public static bool Prefix(ushort buildingID, ref Building data, TransferManager.TransferReason reason,
                                  TransferManager.TransferOffer offer)
        {
            Debug.Log("Start Transfer Called");
            if (DistrictHelper.CanTransfer(buildingID, reason, offer))
            {
                Debug.Log("Transfer Request Accepted.");
                return(true);
            }

            BuildingHelper.MoveRequest(buildingID, ref data, reason, offer);
            {
                Debug.Log("Moving Transfer Request.");
                return(false);
            }
        }
        public static bool Prefix(TransferManager.TransferReason material, ref TransferManager.TransferOffer offer)
        {
            Logger.LogMaterial($"TransferManager::AddIncomingOffer: {Utils.ToString(ref offer, material)}!", material);

            // Inactive outside connections should not be adding offers ...
            if (OutsideConnectionInfo.IsInvalidIncomingOutsideConnection(offer.Building))
            {
                Logger.LogMaterial($"TransferManager::AddIncomingOffer: Disallowing outside connection B{offer.Building} because of missing cargo buildings!", material);
                return(false);
            }

            if (!(TransferManagerInfo.IsDistrictOffer(material) || TransferManagerInfo.IsSupplyChainOffer(material)))
            {
                // Fix for certain assets that have sub buildings that should not be making offers ...
                if (offer.Building != 0 && BuildingManager.instance.m_buildings.m_buffer[offer.Building].m_parentBuilding != 0)
                {
                    if (material == TransferManager.TransferReason.ParkMaintenance)
                    {
                        Logger.LogMaterial($"TransferManager::AddIncomingOffer: Filtering out subBuilding {Utils.ToString(ref offer, material)}!", material);
                        return(false);
                    }
                }

                return(true);
            }

            if (material == TransferManager.TransferReason.Taxi && offer.Citizen != 0)
            {
                var instance       = CitizenManager.instance.m_citizens.m_buffer[offer.Citizen].m_instance;
                var targetBuilding = CitizenManager.instance.m_instances.m_buffer[instance].m_targetBuilding;
                var targetPosition = BuildingManager.instance.m_buildings.m_buffer[targetBuilding].m_position;

                if (!TaxiMod.CanUseTaxis(offer.Position, targetPosition))
                {
                    Logger.LogMaterial($"TransferManager::AddIncomingOffer: Filtering out {Utils.ToString(ref offer, material)}!", material);
                    var instanceId = CitizenManager.instance.m_citizens.m_buffer[offer.Citizen].m_instance;
                    CitizenManager.instance.m_instances.m_buffer[instanceId].m_flags      &= ~CitizenInstance.Flags.WaitingTaxi;
                    CitizenManager.instance.m_instances.m_buffer[instanceId].m_flags      |= CitizenInstance.Flags.BoredOfWaiting;
                    CitizenManager.instance.m_instances.m_buffer[instanceId].m_flags      |= CitizenInstance.Flags.CannotUseTaxi;
                    CitizenManager.instance.m_instances.m_buffer[instanceId].m_waitCounter = byte.MaxValue;
                    return(false);
                }
            }

            TransferManagerAddOffer.ModifyOffer(material, ref offer);
            return(true);
        }
        public static bool Prefix(ref TransferManager.TransferReason material, ref TransferManager.TransferOffer offer)
        {
            Logger.LogMaterial($"TransferManager::AddOutgoingOffer: {Utils.ToString(ref offer, material)}!", material);

            // Inactive outside connections should not be adding offers ...
            if (OutsideConnectionInfo.IsInvalidOutgoingOutsideConnection(offer.Building))
            {
                Logger.LogMaterial($"TransferManager::AddOutgoingOffer: Disallowing outside connection B{offer.Building} because of missing cargo buildings!", material);
                return(false);
            }

            // Change these offers ... a bug in the base game.  Citizens should not offer health care services.
            if ((material == TransferManager.TransferReason.ElderCare || material == TransferManager.TransferReason.ChildCare) && offer.Citizen != 0)
            {
                offer.Active = true;
                TransferManager.instance.AddIncomingOffer(material, offer);
                return(false);
            }

            // Too many requests for helicopters ...
            if (material == TransferManager.TransferReason.Sick2)
            {
                if (Singleton <SimulationManager> .instance.m_randomizer.Int32(10U) != 0)
                {
                    material = TransferManager.TransferReason.Sick;
                }
            }

            if (!(TransferManagerInfo.IsDistrictOffer(material) || TransferManagerInfo.IsSupplyChainOffer(material)))
            {
                // Fix for certain assets that have sub buildings that should not be making offers ...
                if (offer.Building != 0 && BuildingManager.instance.m_buildings.m_buffer[offer.Building].m_parentBuilding != 0)
                {
                    if (material == TransferManager.TransferReason.ParkMaintenance)
                    {
                        Logger.LogMaterial($"TransferManager::AddOutgoingOffer: Filtering out subBuilding {Utils.ToString(ref offer, material)}!", material);
                        return(false);
                    }
                }

                return(true);
            }

            TransferManagerAddOffer.ModifyOffer(material, ref offer);
            return(true);
        }
Example #24
0
        public static void Prefix(ref TransferManager.TransferReason material, ref TransferManager.TransferOffer offer)
        {
            if (!CustomTransferManager._init)
            {
                CustomTransferManager.Init();
                CustomTransferManager._init = true;
            }

            //If no HelicopterDepot, change offer type.
            if (!HelicopterDepotAISimulationStepPatch.haveFireHelicopterDepotFinal)
            {
                if (material == TransferManager.TransferReason.Fire2)
                {
                    material = TransferManager.TransferReason.Fire;
                }
            }
        }
        public static bool Prefix(TransferManager.TransferReason material, TransferManager.TransferOffer offerOut, TransferManager.TransferOffer offerIn, int delta)
        {
            bool offerOutActive = offerOut.Active;

            if (offerOutActive && offerOut.Building != 0)
            {
                Array16 <Building> buildings = Singleton <BuildingManager> .instance.m_buildings;
                ushort             building  = offerOut.Building;
                offerIn.Amount = delta;
                if ((material == TransferManager.TransferReason.DeadMove || material == TransferManager.TransferReason.GarbageMove) && Singleton <BuildingManager> .instance.m_buildings.m_buffer[offerOut.Building].m_flags.IsFlagSet(Building.Flags.Untouchable))
                {
                    StartMoreTransfer(building, ref buildings.m_buffer[(int)building], material, offerIn);
                    return(false);
                }
            }
            return(true);
        }
Example #26
0
        public override void BuildingDeactivated(ushort buildingID, ref Building data)
        {
            TransferManager.TransferOffer offer = default(TransferManager.TransferOffer);
            offer.Building = buildingID;
            for (int i = 0; i < m_incomingResources.Length; i++)
            {
                if (m_incomingResources[i] != TransferManager.TransferReason.None)
                {
                    Singleton <TransferManager> .instance.RemoveIncomingOffer(m_incomingResources[i], offer);
                }
            }
            Singleton <TransferManager> .instance.RemoveOutgoingOffer(TransferManager.TransferReason.Entertainment, offer);

            Singleton <TransferManager> .instance.RemoveOutgoingOffer(TransferManager.TransferReason.EntertainmentB, offer);

            Singleton <TransferManager> .instance.RemoveOutgoingOffer(TransferManager.TransferReason.EntertainmentC, offer);

            Singleton <TransferManager> .instance.RemoveOutgoingOffer(TransferManager.TransferReason.EntertainmentD, offer);

            Singleton <TransferManager> .instance.RemoveOutgoingOffer(TransferManager.TransferReason.TouristA, offer);

            Singleton <TransferManager> .instance.RemoveOutgoingOffer(TransferManager.TransferReason.TouristB, offer);

            Singleton <TransferManager> .instance.RemoveOutgoingOffer(TransferManager.TransferReason.TouristC, offer);

            Singleton <TransferManager> .instance.RemoveOutgoingOffer(TransferManager.TransferReason.TouristD, offer);

            Singleton <TransferManager> .instance.RemoveOutgoingOffer(TransferManager.TransferReason.Shopping, offer);

            Singleton <TransferManager> .instance.RemoveOutgoingOffer(TransferManager.TransferReason.ShoppingB, offer);

            Singleton <TransferManager> .instance.RemoveOutgoingOffer(TransferManager.TransferReason.ShoppingC, offer);

            Singleton <TransferManager> .instance.RemoveOutgoingOffer(TransferManager.TransferReason.ShoppingD, offer);

            Singleton <TransferManager> .instance.RemoveOutgoingOffer(TransferManager.TransferReason.ShoppingE, offer);

            Singleton <TransferManager> .instance.RemoveOutgoingOffer(TransferManager.TransferReason.ShoppingF, offer);

            Singleton <TransferManager> .instance.RemoveOutgoingOffer(TransferManager.TransferReason.ShoppingG, offer);

            Singleton <TransferManager> .instance.RemoveOutgoingOffer(TransferManager.TransferReason.ShoppingH, offer);

            base.BuildingDeactivated(buildingID, ref data);
        }
Example #27
0
        public void DispatchIdleVehicle()
        {
            Building[] buildings = Singleton <BuildingManager> .instance.m_buildings.m_buffer;
            Building   me        = buildings[_buildingID];

            if ((me.m_flags & Building.Flags.Active) == Building.Flags.None && me.m_productionRate == 0)
            {
                return;
            }

            if ((me.m_flags & Building.Flags.Downgrading) != Building.Flags.None)
            {
                return;
            }

            if (me.Info.m_buildingAI.IsFull(_buildingID, ref buildings[_buildingID]))
            {
                return;
            }
            int max, now;

            CaluculateWorkingVehicles(out max, out now);

            if (now >= max)
            {
                return;
            }
            ushort target = GetUnclaimedTarget();

            if (target == 0)
            {
                return;
            }

            TransferManager.TransferOffer offer = default(TransferManager.TransferOffer);
            offer.Building = target;
            offer.Position = buildings[target].m_position;

            me.Info.m_buildingAI.StartTransfer(
                _buildingID,
                ref buildings[_buildingID],
                TransferManager.TransferReason.Garbage,
                offer
                );
        }
        /// <summary>
        /// Sets the priority of outside connection offers to 0, while ensuring that local offers have priority 1
        /// or greater.
        /// </summary>
        /// <remarks>
        /// We are a modifying the priority of offers as a way of prioritizing the local supply chain, and only
        /// resorting to outside connections if materials cannot be found locally.
        /// </remarks>
        /// <param name="material"></param>
        /// <param name="offer"></param>
        public static void ModifyOffer(TransferManager.TransferReason material, ref TransferManager.TransferOffer offer)
        {
            var isOutsideOffer = TransferManagerInfo.IsOutsideOffer(ref offer);

            if (isOutsideOffer)
            {
                offer.Priority = 0;
            }
            else
            {
                offer.Priority = Mathf.Clamp(offer.Priority + 1, 1, 7);
            }

            if (offer.Vehicle != 0)
            {
                offer.Priority = 7;
            }
        }
Example #29
0
            private static bool Prefix(TransferManager.TransferReason material, ref TransferManager.TransferOffer offer)
            {
                switch (material)
                {
                case TransferManager.TransferReason.Entertainment:
                case TransferManager.TransferReason.EntertainmentB:
                case TransferManager.TransferReason.EntertainmentC:
                case TransferManager.TransferReason.EntertainmentD:
                case TransferManager.TransferReason.TouristA:
                case TransferManager.TransferReason.TouristB:
                case TransferManager.TransferReason.TouristC:
                case TransferManager.TransferReason.TouristD:
                    return(RealTimeAI?.IsEntertainmentTarget(offer.Building) ?? true);

                default:
                    return(true);
                }
            }
        public static bool Prefix(ushort buildingID, ref Building data, TransferManager.TransferReason material,
                                  TransferManager.TransferOffer offer)
        {
            Debug.Log("Start Transfer Called");
            if (DistrictHelper.CanTransfer(buildingID, material, offer))
            {
                Debug.Log(
                    $"Transfer Request Accepted from {DistrictManager.instance.GetDistrictName(DistrictManager.instance.GetDistrict(data.m_position))}");
                return(true);
            }

            BuildingHelper.MoveRequest(buildingID, ref data, material, offer);
            {
                Debug.Log(
                    $"Moving Transfer Request from {DistrictManager.instance.GetDistrictName(DistrictManager.instance.GetDistrict(data.m_position))}");
                return(false);
            }
        }
        /// <summary>
        /// Starts the transfer.
        /// </summary>
        /// <param name="vehicleId">The vehicle identifier.</param>
        /// <param name="vehicle">The vehicle.</param>
        /// <param name="material">The material.</param>
        /// <param name="targetBuildingId">The target building identifier.</param>
        /// <param name="targetCitizenId">The target citizen identifier.</param>
        /// <returns>True on success.</returns>
        private static bool StartTransfer(ushort vehicleId, ref Vehicle vehicle, TransferManager.TransferReason material, ushort targetBuildingId, uint targetCitizenId)
        {
            TransferManager.TransferOffer offer = new TransferManager.TransferOffer()
            {
                Building = targetBuildingId,
                Citizen = targetCitizenId,
            };

            vehicle.m_flags &= ~Vehicle.Flags.GoingBack;
            vehicle.m_flags |= Vehicle.Flags.WaitingTarget;

            // Cast AI as games original AI so detoured methods are called, but not methods from not replaced classes.
            if (Global.Settings.AssignmentCompatibilityMode == ServiceDispatcherSettings.ModCompatibilityMode.UseInstanciatedClassMethods || !Global.Settings.AllowReflection())
            {
                vehicle.Info.m_vehicleAI.StartTransfer(vehicleId, ref vehicle, material, offer);
            }
            else if (vehicle.Info.m_vehicleAI is HearseAI)
            {
                ((HearseAI)vehicle.Info.m_vehicleAI.CastTo<HearseAI>()).StartTransfer(vehicleId, ref vehicle, material, offer);
            }
            else if (vehicle.Info.m_vehicleAI is GarbageTruckAI)
            {
                ((GarbageTruckAI)vehicle.Info.m_vehicleAI.CastTo<GarbageTruckAI>()).StartTransfer(vehicleId, ref vehicle, material, offer);
            }
            else if (vehicle.Info.m_vehicleAI is AmbulanceAI)
            {
                ((AmbulanceAI)vehicle.Info.m_vehicleAI.CastTo<AmbulanceAI>()).StartTransfer(vehicleId, ref vehicle, material, offer);
            }
            else
            {
                vehicle.Info.m_vehicleAI.StartTransfer(vehicleId, ref vehicle, material, offer);
            }

            return vehicle.m_targetBuilding == targetBuildingId && (targetCitizenId == 0 || Singleton<CitizenManager>.instance.m_citizens.m_buffer[targetCitizenId].m_vehicle == vehicleId);
        }
 private bool FindHospital(uint citizenID, ushort sourceBuilding, TransferManager.TransferReason reason)
 {
     if (reason == TransferManager.TransferReason.Dead)
     {
         if (Singleton<UnlockManager>.instance.Unlocked(UnlockManager.Feature.DeathCare))
         {
             return true;
         }
        ReleaseCitizen(citizenID);
         return false;
     }
     if (Singleton<UnlockManager>.instance.Unlocked(ItemClass.Service.HealthCare))
     {
         TransferManager.TransferOffer offer = new TransferManager.TransferOffer
         {
             Priority = 6,
             Citizen = citizenID,
             Position = Singleton<BuildingManager>.instance.m_buildings.m_buffer[sourceBuilding].m_position,
             Amount = 1,
             Active = Singleton<SimulationManager>.instance.m_randomizer.Int32(2) == 0
         };
         Singleton<TransferManager>.instance.AddOutgoingOffer(reason, offer);
         return true;
     }
        ReleaseCitizen(citizenID);
     return false;
 }
        private void UpdateWorkplace(uint citizenID, ref Citizen data)
        {
            if ((data.m_workBuilding == 0) && (data.m_homeBuilding != 0))
            {
                Vector3 position = Singleton<BuildingManager>.instance.m_buildings.m_buffer[data.m_homeBuilding].m_position;
                DistrictManager instance = Singleton<DistrictManager>.instance;
                byte district = instance.GetDistrict(position);
                DistrictPolicies.Services servicePolicies = instance.m_districts.m_buffer[district].m_servicePolicies;
                int age = data.Age;
                TransferManager.TransferReason none = TransferManager.TransferReason.None;
                switch (Citizen.GetAgeGroup(age))
                {
                    case Citizen.AgeGroup.Child:
                        if (!data.Education1)
                        {
                            none = TransferManager.TransferReason.Student1;
                        }
                        break;

                    case Citizen.AgeGroup.Teen:
                        if (!data.Education2)
                        {
                            none = TransferManager.TransferReason.Student2;
                        }
                        break;

                    case Citizen.AgeGroup.Young:
                    case Citizen.AgeGroup.Adult:
                        if (!data.Education3)
                        {
                            none = TransferManager.TransferReason.Student3;
                        }
                        break;
                }
                if (((data.Unemployed != 0) && (data.m_homeBuilding != 0)) && ((((servicePolicies & DistrictPolicies.Services.EducationBoost) == DistrictPolicies.Services.None) || (none != TransferManager.TransferReason.Student3)) || ((age % 5) > 2)))
                {
                    TransferManager.TransferOffer offer = new TransferManager.TransferOffer
                    {
                        Priority = Singleton<SimulationManager>.instance.m_randomizer.Int32(8),
                        Citizen = citizenID,
                        Position = position,
                        Amount = 1,
                        Active = true
                    };
                    switch (data.EducationLevel)
                    {
                        case Citizen.Education.Uneducated:
                            Singleton<TransferManager>.instance.AddOutgoingOffer(TransferManager.TransferReason.Worker0, offer);
                            break;

                        case Citizen.Education.OneSchool:
                            Singleton<TransferManager>.instance.AddOutgoingOffer(TransferManager.TransferReason.Worker1, offer);
                            break;

                        case Citizen.Education.TwoSchools:
                            Singleton<TransferManager>.instance.AddOutgoingOffer(TransferManager.TransferReason.Worker2, offer);
                            break;

                        case Citizen.Education.ThreeSchools:
                            Singleton<TransferManager>.instance.AddOutgoingOffer(TransferManager.TransferReason.Worker3, offer);
                            break;
                    }
                }
                if (none != TransferManager.TransferReason.None && (none != TransferManager.TransferReason.Student3 || (servicePolicies & DistrictPolicies.Services.SchoolsOut) == DistrictPolicies.Services.None || age % 5 > 1))
                {
                    TransferManager.TransferOffer offer2 = new TransferManager.TransferOffer
                    {
                        Priority = Singleton<SimulationManager>.instance.m_randomizer.Int32(8),
                        Citizen = citizenID,
                        Position = position,
                        Amount = 1,
                        Active = true
                    };
                    Singleton<TransferManager>.instance.AddOutgoingOffer(none, offer2);
                }
            }
        }
        private void UpdateHome(uint citizenID, ref Citizen data)
        {
            if ((data.m_homeBuilding == 0) && ((data.m_flags & Citizen.Flags.DummyTraffic) == Citizen.Flags.None))
            {
                TransferManager.TransferOffer offer = new TransferManager.TransferOffer
                {
                    Priority = 7,
                    Citizen = citizenID,
                    Amount = 1,
                    Active = true
                };
                if (data.m_workBuilding != 0)
                {
                    BuildingManager instance = Singleton<BuildingManager>.instance;
                    offer.Position = instance.m_buildings.m_buffer[data.m_workBuilding].m_position;
                }
                else
                {
                    offer.PositionX = Singleton<SimulationManager>.instance.m_randomizer.Int32(0x100);
                    offer.PositionZ = Singleton<SimulationManager>.instance.m_randomizer.Int32(0x100);
                }
                if (Singleton<SimulationManager>.instance.m_randomizer.Int32(2) == 0)
                {
                    switch (data.EducationLevel)
                    {
                        case Citizen.Education.Uneducated:
                            Singleton<TransferManager>.instance.AddOutgoingOffer(TransferManager.TransferReason.Single0, offer);
                            break;

                        case Citizen.Education.OneSchool:
                            Singleton<TransferManager>.instance.AddOutgoingOffer(TransferManager.TransferReason.Single1, offer);
                            break;

                        case Citizen.Education.TwoSchools:
                            Singleton<TransferManager>.instance.AddOutgoingOffer(TransferManager.TransferReason.Single2, offer);
                            break;

                        case Citizen.Education.ThreeSchools:
                            Singleton<TransferManager>.instance.AddOutgoingOffer(TransferManager.TransferReason.Single3, offer);
                            break;
                    }
                }
                else
                {
                    switch (data.EducationLevel)
                    {
                        case Citizen.Education.Uneducated:
                            Singleton<TransferManager>.instance.AddOutgoingOffer(TransferManager.TransferReason.Single0B, offer);
                            break;

                        case Citizen.Education.OneSchool:
                            Singleton<TransferManager>.instance.AddOutgoingOffer(TransferManager.TransferReason.Single1B, offer);
                            break;

                        case Citizen.Education.TwoSchools:
                            Singleton<TransferManager>.instance.AddOutgoingOffer(TransferManager.TransferReason.Single2B, offer);
                            break;

                        case Citizen.Education.ThreeSchools:
                            Singleton<TransferManager>.instance.AddOutgoingOffer(TransferManager.TransferReason.Single3B, offer);
                            break;
                    }
                }
            }
        }
        /// <summary>
        /// Starts the transfer.
        /// </summary>
        /// <param name="serviceBuildingId">The building identifier.</param>
        /// <param name="building">The building.</param>
        /// <param name="material">The material.</param>
        /// <param name="targetBuildingId">The target building identifier.</param>
        /// <param name="targetCitizenId">The target citizen identifier.</param>
        /// <param name="vehicleId">The vehicle identifier.</param>
        /// <returns>Vehicle info for the created vehicle.</returns>
        /// <exception cref="Exception">Loop counter too high.</exception>
        public static VehicleInfo StartTransfer(ushort serviceBuildingId, ref Building building, TransferManager.TransferReason material, ushort targetBuildingId, uint targetCitizenId, out ushort vehicleId)
        {
            if (building.Info.m_buildingAI is HospitalAI && targetCitizenId == 0)
            {
                return VehicleHelper.CreateServiceVehicle(serviceBuildingId, material, targetBuildingId, targetCitizenId, out vehicleId);
            }

            Vehicle[] vehicles = Singleton<VehicleManager>.instance.m_vehicles.m_buffer;
            Citizen[] citizens = Singleton<CitizenManager>.instance.m_citizens.m_buffer;

            TransferManager.TransferOffer offer = new TransferManager.TransferOffer()
            {
                Building = targetBuildingId,
                Citizen = targetCitizenId,
            };

            // Cast AI as games original AI so detoured methods are called, but not methods from not replaced classes.
            if (Global.Settings.CreationCompatibilityMode == ServiceDispatcherSettings.ModCompatibilityMode.UseInstanciatedClassMethods || !Global.Settings.AllowReflection())
            {
                building.Info.m_buildingAI.StartTransfer(serviceBuildingId, ref building, material, offer);
            }
            else if (building.Info.m_buildingAI is CemeteryAI)
            {
                ((CemeteryAI)building.Info.m_buildingAI.CastTo<CemeteryAI>()).StartTransfer(serviceBuildingId, ref building, material, offer);
            }
            else if (building.Info.m_buildingAI is LandfillSiteAI)
            {
                ((LandfillSiteAI)building.Info.m_buildingAI.CastTo<LandfillSiteAI>()).StartTransfer(serviceBuildingId, ref building, material, offer);
            }
            else if (building.Info.m_buildingAI is HospitalAI)
            {
                ((HospitalAI)building.Info.m_buildingAI.CastTo<HospitalAI>()).StartTransfer(serviceBuildingId, ref building, material, offer);
            }
            else
            {
                building.Info.m_buildingAI.StartTransfer(serviceBuildingId, ref building, material, offer);
            }

            int count = 0;
            vehicleId = building.m_ownVehicles;
            while (vehicleId != 0)
            {
                if (vehicles[vehicleId].m_targetBuilding == targetBuildingId && (targetCitizenId == 0 || citizens[targetCitizenId].m_vehicle == vehicleId))
                {
                    return vehicles[vehicleId].Info;
                }

                if (count >= ushort.MaxValue)
                {
                    throw new Exception("Loop counter too high");
                }

                count++;
                vehicleId = vehicles[vehicleId].m_nextOwnVehicle;
            }

            return null;
        }