Beispiel #1
0
        private void ReturnFromVisit(
            TAI instance,
            uint citizenId,
            ref TCitizen citizen,
            ushort targetBuilding,
            Citizen.Location targetLocation,
            bool isVirtual)
        {
            if (targetBuilding == 0 || targetLocation == Citizen.Location.Visit || CitizenProxy.GetVehicle(ref citizen) != 0)
            {
                return;
            }

            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            CitizenProxy.RemoveFlags(ref citizen, Citizen.Flags.Evacuating);
            CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);

            if (isVirtual || targetBuilding == currentBuilding)
            {
                CitizenProxy.SetLocation(ref citizen, targetLocation);
            }
            else
            {
                residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, targetBuilding);
            }
        }
        private bool ProcessCitizenSick(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            Citizen.Location currentLocation = CitizenProxy.GetLocation(ref citizen);
            if (currentLocation == Citizen.Location.Moving)
            {
                return(false);
            }

            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            if (currentLocation != Citizen.Location.Home && currentBuilding == 0)
            {
                Log.Debug(LogCategory.State, $"Teleporting {GetCitizenDesc(citizenId, ref citizen)} back home because they are sick but no building is specified");
                CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home);
                return(true);
            }

            if (currentLocation != Citizen.Location.Home && CitizenProxy.GetVehicle(ref citizen) != 0)
            {
                return(true);
            }

            if (currentLocation == Citizen.Location.Visit)
            {
                ItemClass.Service service = BuildingMgr.GetBuildingService(CitizenProxy.GetVisitBuilding(ref citizen));
                if (service == ItemClass.Service.HealthCare || service == ItemClass.Service.Disaster)
                {
                    return(true);
                }
            }

            Log.Debug(LogCategory.State, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is sick, trying to get to a hospital");
            residentAI.FindHospital(instance, citizenId, currentBuilding, TransferManager.TransferReason.Sick);
            return(true);
        }
Beispiel #3
0
 public ExtCitizen(uint citizenId)
 {
     this.citizenId    = citizenId;
     transportMode     = ExtTransportMode.None;
     lastTransportMode = ExtTransportMode.None;
     lastLocation      = Citizen.Location.Moving;
 }
 internal ExtCitizen(uint citizenId)
 {
     this.citizenId    = citizenId;
     transportMode     = ExtTransportMode.None;
     lastTransportMode = ExtTransportMode.None;
     lastLocation      = Citizen.Location.Moving;
     ResetLastLocation();
 }
 private void ResetLastLocation()
 {
     Citizen.Location loc = Citizen.Location.Moving;
     Constants.ServiceFactory.CitizenService.ProcessCitizen(citizenId, delegate(uint citId, ref Citizen citizen) {
         loc = citizen.CurrentLocation;
         return(true);
     });
     lastLocation = loc;
 }
Beispiel #6
0
        /// <summary>
        /// Gets a string that describes the specified citizen.
        /// </summary>
        ///
        /// <param name="citizenId">The citizen ID.</param>
        /// <param name="citizen">The citizen data reference.</param>
        ///
        /// <returns>A short string describing the specified citizen.</returns>
        protected string GetCitizenDesc(uint citizenId, ref TCitizen citizen)
        {
            ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen);
            string home         = homeBuilding == 0 ? "homeless" : "lives at " + homeBuilding;
            ushort workBuilding = CitizenProxy.GetWorkBuilding(ref citizen);
            string employment   = workBuilding == 0 ? "unemployed" : "works at " + workBuilding;

            Citizen.Location location = CitizenProxy.GetLocation(ref citizen);
            return($"Citizen {citizenId} ({CitizenProxy.GetAge(ref citizen)}, {home}, {employment}, currently {location} at {CitizenProxy.GetCurrentBuilding(ref citizen)}) / instance {CitizenProxy.GetInstance(ref citizen)}");
        }
Beispiel #7
0
        /// <summary>
        /// Gets a string that describes the provided citizen.
        /// </summary>
        ///
        /// <param name="citizenId">The citizen ID.</param>
        /// <param name="citizen">The citizen data reference.</param>
        /// <param name="isVirtual"><c>true</c> if the citizen is in a virtual mode; otherwise, <c>false</c>.</param>
        ///
        /// <returns>A short string describing the provided citizen.</returns>
        protected string GetCitizenDesc(uint citizenId, ref TCitizen citizen, bool?isVirtual)
        {
            ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen);
            string home         = homeBuilding == 0 ? "homeless" : "lives at " + homeBuilding;
            ushort workBuilding = CitizenProxy.GetWorkBuilding(ref citizen);
            string employment   = workBuilding == 0 ? "unemployed" : "works at " + workBuilding;

            Citizen.Location location = CitizenProxy.GetLocation(ref citizen);
            string           virt     = isVirtual.HasValue ? (isVirtual.Value ? " (virtual)" : " (real)") : null;

            return($"Citizen {citizenId} ({CitizenProxy.GetAge(ref citizen)}, {home}, {employment}, currently {location} at {CitizenProxy.GetCurrentBuilding(ref citizen)}) / instance {CitizenProxy.GetInstance(ref citizen)}{virt}");
        }
Beispiel #8
0
        private void ProcessCitizenAtSchoolOrWork(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            ushort workBuilding = CitizenProxy.GetWorkBuilding(ref citizen);

            if (workBuilding == 0)
            {
                Log.Debug($"WARNING: {GetCitizenDesc(citizenId, ref citizen)} is in corrupt state: at school/work with no work building. Teleporting home.");
                CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home);
                return;
            }

            if (ShouldGoToLunch(CitizenProxy.GetAge(ref citizen)))
            {
                ushort           currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);
                Citizen.Location currentLocation = CitizenProxy.GetLocation(ref citizen);

                ushort lunchPlace = MoveToCommercialBuilding(instance, citizenId, ref citizen, LocalSearchDistance);
                if (lunchPlace != 0)
                {
                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is going for lunch from {currentBuilding} ({currentLocation}) to {lunchPlace}");
                }
                else
                {
                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted to go for lunch from {currentBuilding} ({currentLocation}), but there were no buildings close enough");
                }

                return;
            }

            if (!ShouldReturnFromSchoolOrWork(CitizenProxy.GetAge(ref citizen)))
            {
                return;
            }

            Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} leaves their workplace {workBuilding}");

            if (CitizenGoesToEvent(instance, citizenId, ref citizen))
            {
                return;
            }

            if (!CitizenGoesShopping(instance, citizenId, ref citizen) && !CitizenGoesRelaxing(instance, citizenId, ref citizen))
            {
                residentAI.StartMoving(instance, citizenId, ref citizen, workBuilding, CitizenProxy.GetHomeBuilding(ref citizen));
            }
        }
        private void ProcessCitizenDead(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            Citizen.Location currentLocation = CitizenProxy.GetLocation(ref citizen);
            switch (currentLocation)
            {
            case Citizen.Location.Home when currentBuilding != 0:
                CitizenProxy.SetWorkplace(ref citizen, citizenId, 0);
                CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
                break;

            case Citizen.Location.Work when currentBuilding != 0:
                CitizenProxy.SetHome(ref citizen, citizenId, 0);
                CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
                break;

            case Citizen.Location.Visit when currentBuilding != 0:
                CitizenProxy.SetHome(ref citizen, citizenId, 0);
                CitizenProxy.SetWorkplace(ref citizen, citizenId, 0);

                if (BuildingMgr.GetBuildingService(CitizenProxy.GetVisitBuilding(ref citizen)) == ItemClass.Service.HealthCare)
                {
                    return;
                }

                break;

            case Citizen.Location.Moving when CitizenProxy.GetVehicle(ref citizen) != 0:
                CitizenProxy.SetHome(ref citizen, citizenId, 0);

                CitizenProxy.SetWorkplace(ref citizen, citizenId, 0);
                CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
                return;

            default:
                Log.Debug(LogCategory.State, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is released because of death");
                residentSchedules[citizenId] = default;
                CitizenMgr.ReleaseCitizen(citizenId);
                return;
            }

            residentAI.FindHospital(instance, citizenId, currentBuilding, TransferManager.TransferReason.Dead);
            Log.Debug(LogCategory.State, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is dead, body should get serviced");
        }
Beispiel #10
0
        /// <summary>
        /// Check if resident is confused.
        /// </summary>
        /// <param name="data">The citizen.</param>
        /// <returns>True if resident is confused.</returns>
        public static bool IsConfused(ref Citizen data)
        {
            // From ResidentAI.GetLocalizedStatus from original game code at version 1.7.0-f5.
            CitizenManager instance1 = Singleton <CitizenManager> .instance;
            ushort         instance2 = data.m_instance;

            if ((int)instance2 != 0)
            {
                return(IsConfused(ref instance1.m_instances.m_buffer[(int)instance2]));
            }
            Citizen.Location currentLocation = data.CurrentLocation;
            ushort           homeBuilding    = data.m_homeBuilding;
            ushort           workBuilding    = data.m_workBuilding;
            ushort           visitBuilding   = data.m_visitBuilding;

            //bool flag = (data.m_flags & Citizen.Flags.Student) != Citizen.Flags.None;
            if (currentLocation != Citizen.Location.Home)
            {
                if (currentLocation != Citizen.Location.Work)
                {
                    if (currentLocation == Citizen.Location.Visit && (int)visitBuilding != 0)
                    {
                        //target = InstanceID.Empty;
                        //target.Building = visitBuilding;
                        //return ColossalFramework.Globalization.Locale.Get("CITIZEN_STATUS_VISITING");
                        return(false);
                    }
                }
                else if ((int)workBuilding != 0)
                {
                    //target = InstanceID.Empty;
                    //return ColossalFramework.Globalization.Locale.Get(!flag ? "CITIZEN_STATUS_AT_WORK" : "CITIZEN_STATUS_AT_SCHOOL");
                    return(false);
                }
            }
            else if ((int)homeBuilding != 0)
            {
                //target = InstanceID.Empty;
                //return ColossalFramework.Globalization.Locale.Get("CITIZEN_STATUS_AT_HOME");
                return(false);
            }
            //target = InstanceID.Empty;
            //return ColossalFramework.Globalization.Locale.Get("CITIZEN_STATUS_CONFUSED");
            return(true);
        }
        private void ProcessCitizenDead(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            Citizen.Location currentLocation = CitizenProxy.GetLocation(ref citizen);

            if (currentBuilding == 0 || (currentLocation == Citizen.Location.Moving && CitizenProxy.GetVehicle(ref citizen) == 0))
            {
                Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is released");
                residentSchedules[citizenId] = default;
                CitizenMgr.ReleaseCitizen(citizenId);
                return;
            }

            if (currentLocation != Citizen.Location.Home && CitizenProxy.GetHomeBuilding(ref citizen) != 0)
            {
                CitizenProxy.SetHome(ref citizen, citizenId, 0);
            }

            if (currentLocation != Citizen.Location.Work && CitizenProxy.GetWorkBuilding(ref citizen) != 0)
            {
                CitizenProxy.SetWorkplace(ref citizen, citizenId, 0);
            }

            if (currentLocation != Citizen.Location.Visit && CitizenProxy.GetVisitBuilding(ref citizen) != 0)
            {
                CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
            }

            if (currentLocation == Citizen.Location.Moving || CitizenProxy.GetVehicle(ref citizen) != 0)
            {
                return;
            }

            if (currentLocation == Citizen.Location.Visit &&
                BuildingMgr.GetBuildingService(CitizenProxy.GetVisitBuilding(ref citizen)) == ItemClass.Service.HealthCare)
            {
                return;
            }

            residentAI.FindHospital(instance, citizenId, currentBuilding, TransferManager.TransferReason.Dead);
            Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is dead, body should get serviced");
        }
        /// <summary>
        /// Check if tourist is confused.
        /// </summary>
        /// <param name="data">The citizen.</param>
        /// <returns>True if tourist is confused.</returns>
        public static bool IsConfused(ref Citizen data)
        {
            // From TouristAI.GetLocalizedStatus from original game code at version 1.4.1-f2.
            CitizenManager instance   = Singleton <CitizenManager> .instance;
            ushort         instanceID = data.m_instance;

            if ((int)instanceID != 0)
            {
                return(IsConfused(ref instance.m_instances.m_buffer[(int)instanceID]));
            }
            Citizen.Location currentLocation = data.CurrentLocation;
            ushort           num             = data.m_visitBuilding;

            if (currentLocation == Citizen.Location.Visit && (int)num != 0)
            {
                ////target = InstanceID.Empty;
                ////target.Building = num;
                ////return Locale.Get("CITIZEN_STATUS_VISITING");
                return(false);
            }
            ////target = InstanceID.Empty;
            ////return Locale.Get("CITIZEN_STATUS_CONFUSED");
            return(true);
        }
Beispiel #13
0
 public void SetLocation(ref Citizen citizen, Citizen.Location location)
 {
     citizen.CurrentLocation = location;
 }
        private ScheduleAction UpdateCitizenState(ref TCitizen citizen, ref CitizenSchedule schedule)
        {
            if (schedule.CurrentState == ResidentState.Ignored)
            {
                return(ScheduleAction.Ignore);
            }

            if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.DummyTraffic))
            {
                schedule.CurrentState = ResidentState.Ignored;
                return(ScheduleAction.Ignore);
            }

            Citizen.Location location = CitizenProxy.GetLocation(ref citizen);
            if (location == Citizen.Location.Moving)
            {
                if (CitizenMgr.InstanceHasFlags(
                        CitizenProxy.GetInstance(ref citizen),
                        CitizenInstance.Flags.OnTour | CitizenInstance.Flags.TargetIsNode,
                        true))
                {
                    // Guided tours are treated as visits
                    schedule.CurrentState = ResidentState.Visiting;
                    schedule.Hint         = ScheduleHint.OnTour;
                    return(ScheduleAction.ProcessState);
                }

                return(ScheduleAction.ProcessTransition);
            }

            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            if (currentBuilding == 0)
            {
                schedule.CurrentState = ResidentState.Unknown;
                return(ScheduleAction.ProcessState);
            }

            ItemClass.Service buildingService = BuildingMgr.GetBuildingService(currentBuilding);
            if (BuildingMgr.BuildingHasFlags(currentBuilding, Building.Flags.Evacuating) &&
                buildingService != ItemClass.Service.Disaster)
            {
                schedule.CurrentState = ResidentState.Evacuation;
                schedule.Schedule(ResidentState.InShelter);
                return(ScheduleAction.ProcessState);
            }

            switch (location)
            {
            case Citizen.Location.Home:
                schedule.CurrentState = ResidentState.AtHome;
                return(ScheduleAction.ProcessState);

            case Citizen.Location.Work:
                if (buildingService == ItemClass.Service.Disaster && CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating))
                {
                    schedule.CurrentState = ResidentState.InShelter;
                    return(ScheduleAction.ProcessState);
                }

                if (CitizenProxy.GetVisitBuilding(ref citizen) == currentBuilding && schedule.WorkStatus != WorkStatus.Working)
                {
                    // A citizen may visit their own work building (e.g. shopping),
                    // but the game sets the location to 'work' even if the citizen visits the building.
                    goto case Citizen.Location.Visit;
                }

                schedule.CurrentState = ResidentState.AtSchoolOrWork;
                return(ScheduleAction.ProcessState);

            case Citizen.Location.Visit:
                switch (buildingService)
                {
                case ItemClass.Service.Beautification:
                case ItemClass.Service.Monument:
                case ItemClass.Service.Tourism:
                case ItemClass.Service.Commercial
                    when BuildingMgr.GetBuildingSubService(currentBuilding) == ItemClass.SubService.CommercialLeisure &&
                    schedule.WorkStatus != WorkStatus.Working:

                    schedule.CurrentState = ResidentState.Relaxing;

                    return(ScheduleAction.ProcessState);

                case ItemClass.Service.Commercial:
                    schedule.CurrentState = ResidentState.Shopping;
                    return(ScheduleAction.ProcessState);

                case ItemClass.Service.Disaster when CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating):
                    schedule.CurrentState = ResidentState.InShelter;

                    return(ScheduleAction.ProcessState);
                }

                schedule.CurrentState = ResidentState.Visiting;
                return(ScheduleAction.ProcessState);
            }

            return(ScheduleAction.Ignore);
        }
Beispiel #15
0
        /// <summary>
        /// Generic stuff that can be taken care of as a group.
        /// </summary>
        /// <param name="thisAI"></param>
        /// <param name="citizenID"></param>
        /// <param name="person"></param>
        /// <returns>Whether to continue or whether this has taken care of the resident.</returns>
        private static bool ProcessGenerics(ref ResidentAI thisAI, uint citizenID, ref Citizen person)
        {
            bool   everythingOk     = false;
            ushort residingBuilding = 0;

            CitizenManager _citizenManager = Singleton <CitizenManager> .instance;

            Citizen.Location _currentLocation = person.CurrentLocation;

            switch (_currentLocation)
            {
            case Citizen.Location.Home:
                residingBuilding = person.m_homeBuilding;
                break;

            case Citizen.Location.Work:
                residingBuilding = person.m_workBuilding;
                break;

            case Citizen.Location.Visit:
                residingBuilding = person.m_visitBuilding;
                break;
            }

            Building visitBuilding = Singleton <BuildingManager> .instance.m_buildings.m_buffer[person.m_visitBuilding];
            bool     inHealthcare  = _currentLocation == Citizen.Location.Visit && residingBuilding != 0 && (visitBuilding.Info.m_class.m_service == ItemClass.Service.HealthCare || visitBuilding.Info.m_class.m_service == ItemClass.Service.Disaster);

            if (person.Dead)
            {
                if (residingBuilding == 0)
                {
                    _citizenManager.ReleaseCitizen(citizenID);
                }
                else
                {
                    if ((_currentLocation == Citizen.Location.Work || _currentLocation == Citizen.Location.Visit) && person.m_homeBuilding != 0)
                    {
                        person.SetWorkplace(citizenID, 0, 0U);
                    }

                    if ((_currentLocation == Citizen.Location.Home || _currentLocation == Citizen.Location.Visit) && person.m_workBuilding != 0)
                    {
                        person.SetWorkplace(citizenID, 0, 0U);
                    }

                    if ((_currentLocation == Citizen.Location.Home || _currentLocation == Citizen.Location.Work) && person.m_visitBuilding != 0)
                    {
                        person.SetVisitplace(citizenID, 0, 0U);
                    }

                    if (ExperimentsToggle.ImprovedDeathcare)
                    {
                        if (person.m_vehicle == 0 && !inHealthcare)
                        {
                            NewResidentAI.FindHospital(thisAI, citizenID, residingBuilding, TransferManager.TransferReason.Sick);
                        }
                    }
                    else
                    {
                        if (person.m_vehicle == 0 && !inHealthcare)
                        {
                            NewResidentAI.FindHospital(thisAI, citizenID, residingBuilding, TransferManager.TransferReason.Dead);
                        }
                    }
                }
            }
            else if (person.Arrested)
            {
                if (_currentLocation == Citizen.Location.Visit && residingBuilding == 0)
                {
                    person.Arrested = false;
                }
                else
                {
                    person.Arrested = false;
                }
            }
            else if (person.Sick)
            {
                if (residingBuilding != 0)
                {
                    if (person.m_vehicle == 0 && !inHealthcare)
                    {
                        NewResidentAI.FindHospital(thisAI, citizenID, residingBuilding, TransferManager.TransferReason.Sick);
                    }
                }
                else
                {
                    person.CurrentLocation = Citizen.Location.Home;
                }
            }
            else if (residingBuilding == 0)
            {
                person.CurrentLocation = Citizen.Location.Home;
            }
            else if (ShouldEvacuate(residingBuilding))
            {
                NewResidentAI.FindEvacuationPlace(thisAI, citizenID, residingBuilding, NewResidentAI.GetEvacuationReason(thisAI, residingBuilding));
            }
            else if (!person.Collapsed)
            {
                everythingOk = true;
            }

            return(everythingOk);
        }
Beispiel #16
0
        public bool IsAtOutsideConnection(ushort instanceId, ref CitizenInstance instanceData, ref Citizen citizenData)
        {
#if DEBUG
            bool citDebug  = GlobalConfig.Instance.Debug.CitizenId == 0 || GlobalConfig.Instance.Debug.CitizenId == instanceData.m_citizen;
            bool debug     = GlobalConfig.Instance.Debug.Switches[2] && citDebug;
            bool fineDebug = GlobalConfig.Instance.Debug.Switches[4] && citDebug;

            if (debug)
            {
                Log._Debug($"ExtCitizenInstanceManager.IsAtOutsideConnection({instanceId}): called for citizen instance {instanceId}. Path: {instanceData.m_path} vehicle={citizenData.m_vehicle}");
            }
#endif

            Citizen.Location location = citizenData.CurrentLocation;
            switch (location)
            {
            case Citizen.Location.Home:
            case Citizen.Location.Visit:
            case Citizen.Location.Work:
#if DEBUG
                if (fineDebug)
                {
                    Log._Debug($"ExtCitizenInstanceManager.IsAtOutsideConnection({instanceId}): Citizen is currently at location {location}. This is not an outside connection.");
                }
#endif
                return(false);
            }

            bool spawned = (instanceData.m_flags & CitizenInstance.Flags.Character) != CitizenInstance.Flags.None;
            if (!spawned && (citizenData.m_vehicle == 0 || (Singleton <VehicleManager> .instance.m_vehicles.m_buffer[citizenData.m_vehicle].m_flags & Vehicle.Flags.Spawned) == 0))
            {
#if DEBUG
                if (fineDebug)
                {
                    Log._Debug($"ExtCitizenInstanceManager.IsAtOutsideConnection({instanceId}): Citizen instance is not spawned ({instanceData.m_flags}) and does not have a spawned car. Not at an outside connection.");
                }
#endif
                return(false);
            }

            if (instanceData.m_sourceBuilding == 0)
            {
#if DEBUG
                if (fineDebug)
                {
                    Log._Debug($"ExtCitizenInstanceManager.IsAtOutsideConnection({instanceId}): Citizen instance does not have a source building. Not at an outside connection.");
                }
#endif
                return(false);
            }

            if ((Singleton <BuildingManager> .instance.m_buildings.m_buffer[instanceData.m_sourceBuilding].m_flags & Building.Flags.IncomingOutgoing) == Building.Flags.None)
            {
#if DEBUG
                if (fineDebug)
                {
                    Log._Debug($"ExtCitizenInstanceManager.IsAtOutsideConnection({instanceId}): Source building {instanceData.m_sourceBuilding} is not an outside connection.");
                }
#endif
                return(false);
            }

            Vector3 pos;
            if (spawned)
            {
                pos = instanceData.GetLastFramePosition();
            }
            else
            {
                pos = Singleton <VehicleManager> .instance.m_vehicles.m_buffer[citizenData.m_vehicle].GetLastFramePosition();
            }

            bool ret = (pos - Singleton <BuildingManager> .instance.m_buildings.m_buffer[instanceData.m_sourceBuilding].m_position).magnitude <= GlobalConfig.Instance.ParkingAI.MaxBuildingToPedestrianLaneDistance;

#if DEBUG
            if (fineDebug)
            {
                Log._Debug($"ExtCitizenInstanceManager.IsAtOutsideConnection({instanceId}): pos={pos}, spawned={spawned}, ret={ret}");
            }
#endif

            return(ret);
        }