Esempio n. 1
0
        private bool StartMovingToVisitBuilding(TAI instance, uint citizenId, ref TCitizen citizen, ushort visitBuilding, bool isVirtual)
        {
            if (visitBuilding == 0)
            {
                return(false);
            }

            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            if (isVirtual || currentBuilding == visitBuilding)
            {
                CitizenProxy.SetVisitPlace(ref citizen, citizenId, visitBuilding);
                CitizenProxy.SetVisitBuilding(ref citizen, visitBuilding);
                CitizenProxy.SetLocation(ref citizen, Citizen.Location.Visit);
                return(true);
            }
            else if (residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, visitBuilding))
            {
                CitizenProxy.SetVisitPlace(ref citizen, citizenId, visitBuilding);
                CitizenProxy.SetVisitBuilding(ref citizen, visitBuilding);
                return(true);
            }

            return(false);
        }
        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);
        }
Esempio n. 3
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);
            }
        }
Esempio n. 4
0
        private bool StartMovingToVisitBuilding(TAI instance, uint citizenId, ref TCitizen citizen, ushort visitBuilding)
        {
            if (visitBuilding == 0)
            {
                return(false);
            }

            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            if (currentBuilding == visitBuilding)
            {
                CitizenProxy.SetVisitPlace(ref citizen, citizenId, visitBuilding);
                CitizenProxy.SetLocation(ref citizen, Citizen.Location.Visit);
                return(true);
            }

            CitizenProxy.SetVisitPlace(ref citizen, citizenId, visitBuilding);
            if (CitizenProxy.GetVisitBuilding(ref citizen) == 0)
            {
                // Building is full and doesn't accept visitors anymore
                return(false);
            }

            if (!residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, visitBuilding))
            {
                CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
                return(false);
            }

            return(true);
        }
Esempio n. 5
0
        private void DoScheduledWork(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen)
        {
            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            schedule.WorkStatus          = WorkStatus.Working;
            schedule.DepartureToWorkTime = default;

            if (currentBuilding == schedule.WorkBuilding && schedule.CurrentState != ResidentState.AtSchoolOrWork)
            {
                CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
                CitizenProxy.SetLocation(ref citizen, Citizen.Location.Work);
            }
            else if (residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, schedule.WorkBuilding) &&
                     schedule.CurrentState == ResidentState.AtHome)
            {
                schedule.DepartureToWorkTime = TimeInfo.Now;
            }

            Citizen.AgeGroup citizenAge = CitizenProxy.GetAge(ref citizen);
            if (workBehavior.ScheduleLunch(ref schedule, citizenAge))
            {
                Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is going from {currentBuilding} to school/work {schedule.WorkBuilding} and will go to lunch at {schedule.ScheduledStateTime}");
            }
            else
            {
                workBehavior.ScheduleReturnFromWork(ref schedule, citizenAge);
                Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is going from {currentBuilding} to school/work {schedule.WorkBuilding} and will leave work at {schedule.ScheduledStateTime}");
            }
        }
Esempio n. 6
0
        private void ProcessCitizenVisit(TAI instance, ResidentState citizenState, uint citizenId, ref TCitizen citizen, bool isVirtual)
        {
            ushort currentBuilding = CitizenProxy.GetVisitBuilding(ref citizen);

            if (currentBuilding == 0)
            {
                Log.Debug($"WARNING: {GetCitizenDesc(citizenId, ref citizen, isVirtual)} is in corrupt state: visiting with no visit building. Teleporting home.");
                CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home);
                return;
            }

            switch (citizenState)
            {
            case ResidentState.AtLunch:
                CitizenReturnsFromLunch(instance, citizenId, ref citizen, isVirtual);

                return;

            case ResidentState.AtLeisureArea:
                if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.NeedGoods) &&
                    BuildingMgr.GetBuildingSubService(currentBuilding) == ItemClass.SubService.CommercialLeisure)
                {
                    // No Citizen.Flags.NeedGoods flag reset here, because we only bought 'beer' or 'champagne' in a leisure building.
                    BuildingMgr.ModifyMaterialBuffer(CitizenProxy.GetVisitBuilding(ref citizen), TransferManager.TransferReason.Shopping, -ShoppingGoodsAmount);
                }

                goto case ResidentState.Visiting;

            case ResidentState.Visiting:
                if (!CitizenGoesWorking(instance, citizenId, ref citizen, isVirtual))
                {
                    CitizenReturnsHomeFromVisit(instance, citizenId, ref citizen, isVirtual);
                }

                return;

            case ResidentState.Shopping:
                if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.NeedGoods))
                {
                    BuildingMgr.ModifyMaterialBuffer(CitizenProxy.GetVisitBuilding(ref citizen), TransferManager.TransferReason.Shopping, -ShoppingGoodsAmount);
                    CitizenProxy.RemoveFlags(ref citizen, Citizen.Flags.NeedGoods);
                }

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

                if (Random.ShouldOccur(ReturnFromShoppingChance) || IsWorkDayMorning(CitizenProxy.GetAge(ref citizen)))
                {
                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} returning from shopping at {currentBuilding} back home");
                    ReturnFromVisit(instance, citizenId, ref citizen, CitizenProxy.GetHomeBuilding(ref citizen), Citizen.Location.Home, isVirtual);
                }

                return;
            }
        }
Esempio n. 7
0
        private void ProcessCitizenAtSchoolOrWork(TAI instance, uint citizenId, ref TCitizen citizen, bool isVirtual)
        {
            ushort workBuilding = CitizenProxy.GetWorkBuilding(ref citizen);

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

            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

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

                return;
            }

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

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

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

            if (!CitizenGoesShopping(instance, citizenId, ref citizen, isVirtual) && !CitizenGoesRelaxing(instance, citizenId, ref citizen, isVirtual))
            {
                if (isVirtual)
                {
                    CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home);
                }
                else
                {
                    residentAI.StartMoving(instance, citizenId, ref citizen, workBuilding, CitizenProxy.GetHomeBuilding(ref citizen));
                }
            }
        }
Esempio n. 8
0
        private bool ProcessCitizenMoving(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen)
        {
            ushort instanceId = CitizenProxy.GetInstance(ref citizen);
            ushort vehicleId  = CitizenProxy.GetVehicle(ref citizen);

            if (vehicleId == 0 && instanceId == 0)
            {
                if (CitizenProxy.GetVisitBuilding(ref citizen) != 0)
                {
                    CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
                }

                if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.MovingIn))
                {
                    CitizenMgr.ReleaseCitizen(citizenId);
                    schedule = default;
                }
                else
                {
                    CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home);
                    CitizenProxy.SetArrested(ref citizen, false);
                    schedule.Schedule(ResidentState.Unknown);
                }

                return(true);
            }

            if (vehicleId == 0 && CitizenMgr.IsAreaEvacuating(instanceId) && !CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating))
            {
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} was on the way, but the area evacuates. Finding an evacuation place.");
                schedule.Schedule(ResidentState.Unknown);
                TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, residentAI.GetEvacuationReason(instance, 0));
                return(true);
            }

            ushort targetBuilding = CitizenMgr.GetTargetBuilding(instanceId);

            if (targetBuilding == CitizenProxy.GetWorkBuilding(ref citizen))
            {
                return(true);
            }

            ItemClass.Service targetService = BuildingMgr.GetBuildingService(targetBuilding);
            if (targetService == ItemClass.Service.Beautification && WeatherInfo.IsBadWeather)
            {
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} cancels the trip to a park due to bad weather");
                schedule.Schedule(ResidentState.AtHome);
                return(false);
            }

            return(true);
        }
        private void ProcessCitizenMoving(TAI instance, uint citizenId, ref TCitizen citizen, bool mayCancel)
        {
            ushort instanceId = CitizenProxy.GetInstance(ref citizen);
            ushort vehicleId  = CitizenProxy.GetVehicle(ref citizen);

            // TODO: implement bored of traffic jam trip abandon
            if (vehicleId == 0 && instanceId == 0)
            {
                if (CitizenProxy.GetVisitBuilding(ref citizen) != 0)
                {
                    CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
                }

                Log.Debug($"Teleporting {GetCitizenDesc(citizenId, ref citizen)} back home because they are moving but no instance is specified");
                CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home);
                CitizenProxy.SetArrested(ref citizen, false);

                return;
            }

            if (vehicleId == 0 && CitizenMgr.IsAreaEvacuating(instanceId) && !CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating))
            {
                Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} was on the way, but the area evacuates. Finding an evacuation place.");
                TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, residentAI.GetEvacuationReason(instance, 0));
                return;
            }

            if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.TargetIsNode | CitizenInstance.Flags.OnTour, true))
            {
                ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen);
                if (IsChance(AbandonTourChance) && homeBuilding != 0)
                {
                    CitizenProxy.RemoveFlags(ref citizen, Citizen.Flags.Evacuating);
                    residentAI.StartMoving(instance, citizenId, ref citizen, 0, homeBuilding);
                }
            }
            else if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.WaitingTransport | CitizenInstance.Flags.WaitingTaxi))
            {
                if (mayCancel && CitizenMgr.GetInstanceWaitCounter(instanceId) == 255 && IsChance(AbandonTransportWaitChance))
                {
                    ushort home = CitizenProxy.GetHomeBuilding(ref citizen);
                    if (home == 0)
                    {
                        return;
                    }

                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} doesn't want to wait for transport anymore, goes back home");
                    residentAI.StartMoving(instance, citizenId, ref citizen, 0, home);
                }
            }
        }
Esempio n. 10
0
        private void StartMovingToVisitBuilding(TAI instance, uint citizenId, ref TCitizen citizen, ushort currentBuilding, ushort visitBuilding, bool isVirtual)
        {
            CitizenProxy.SetVisitPlace(ref citizen, citizenId, visitBuilding);
            CitizenProxy.SetVisitBuilding(ref citizen, visitBuilding);

            if (isVirtual)
            {
                CitizenProxy.SetLocation(ref citizen, Citizen.Location.Visit);
                touristAI.AddTouristVisit(instance, citizenId, visitBuilding);
            }
            else
            {
                touristAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, visitBuilding);
            }
        }
        private void DoScheduledWork(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen)
        {
            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            schedule.WorkStatus = WorkStatus.Working;

            if (currentBuilding == schedule.WorkBuilding && schedule.CurrentState != ResidentState.AtSchoolOrWork)
            {
                CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
                CitizenProxy.SetLocation(ref citizen, Citizen.Location.Work);
                return;
            }

#if DEBUG
            string citizenDesc = GetCitizenDesc(citizenId, ref citizen);
#else
            const string citizenDesc = null;
#endif

            if (residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, schedule.WorkBuilding))
            {
                if (schedule.CurrentState != ResidentState.AtHome)
                {
                    // The start moving method will register a departure from any building to work,
                    // but we are only interested in the 'home->work' route.
                    schedule.DepartureTime = default;
                }

                Citizen.AgeGroup citizenAge = CitizenProxy.GetAge(ref citizen);
                if (workBehavior.ScheduleLunch(ref schedule, citizenAge))
                {
                    Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{citizenDesc} is going from {currentBuilding} to school/work {schedule.WorkBuilding} and will go to lunch at {schedule.ScheduledStateTime}");
                }
                else
                {
                    workBehavior.ScheduleReturnFromWork(ref schedule, citizenAge);
                    Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{citizenDesc} is going from {currentBuilding} to school/work {schedule.WorkBuilding} and will leave work at {schedule.ScheduledStateTime}");
                }
            }
            else
            {
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted to go to work from {currentBuilding} but can't, will try once again next time");
                schedule.Schedule(ResidentState.Unknown);
            }
        }
Esempio n. 12
0
        private bool ProcessCitizenSick(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            var 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)
            {
                ushort visitBuilding = CitizenProxy.GetVisitBuilding(ref citizen);
                switch (BuildingMgr.GetBuildingService(visitBuilding))
                {
                case ItemClass.Service.HealthCare:
                    UpdateSickStateOnVisitingHealthcare(citizenId, visitBuilding, ref citizen);
                    return(true);

                case ItemClass.Service.Disaster when !BuildingMgr.BuildingHasFlags(visitBuilding, Building.Flags.Downgrading):
                    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);
        }
Esempio n. 13
0
        private bool CitizenReturnsFromLunch(TAI instance, uint citizenId, ref TCitizen citizen, bool isVirtual)
        {
            if (IsLunchHour)
            {
                return(false);
            }

            ushort workBuilding = CitizenProxy.GetWorkBuilding(ref citizen);

            if (workBuilding != 0)
            {
                Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} returning from lunch to {workBuilding}");
                ReturnFromVisit(instance, citizenId, ref citizen, workBuilding, Citizen.Location.Work, isVirtual);
            }
            else
            {
                Log.Debug($"WARNING: {GetCitizenDesc(citizenId, ref citizen, isVirtual)} is at lunch but no work building. Teleporting home.");
                CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home);
            }

            return(true);
        }
Esempio n. 14
0
        private bool CitizenGoesWorking(TAI instance, uint citizenId, ref TCitizen citizen, bool isVirtual)
        {
            ushort homeBuilding    = CitizenProxy.GetHomeBuilding(ref citizen);
            ushort workBuilding    = CitizenProxy.GetWorkBuilding(ref citizen);
            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            if (!ShouldMoveToSchoolOrWork(citizenId, workBuilding, currentBuilding, CitizenProxy.GetAge(ref citizen)))
            {
                return(false);
            }

            Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} is going from {currentBuilding} to school/work {workBuilding}");

            if (isVirtual)
            {
                CitizenProxy.SetLocation(ref citizen, Citizen.Location.Work);
            }
            else
            {
                residentAI.StartMoving(instance, citizenId, ref citizen, homeBuilding, workBuilding);
            }

            return(true);
        }
Esempio n. 15
0
        /// <summary>The entry method of the custom AI.</summary>
        /// <param name="instance">A reference to an object instance of the original AI.</param>
        /// <param name="citizenId">The ID of the citizen to process.</param>
        /// <param name="citizen">A <typeparamref name="TCitizen"/> reference to process.</param>
        public void UpdateLocation(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            if (!EnsureCitizenCanBeProcessed(citizenId, ref citizen))
            {
                return;
            }

            if (CitizenProxy.IsDead(ref citizen))
            {
                ProcessCitizenDead(instance, citizenId, ref citizen);
                return;
            }

            if ((CitizenProxy.IsSick(ref citizen) && ProcessCitizenSick(instance, citizenId, ref citizen)) ||
                (CitizenProxy.IsArrested(ref citizen) && ProcessCitizenArrested(ref citizen)))
            {
                return;
            }

            ResidentState residentState = GetResidentState(ref citizen);
            bool          isVirtual;

            switch (residentState)
            {
            case ResidentState.MovingHome:
                ProcessCitizenMoving(instance, citizenId, ref citizen, false);
                break;

            case ResidentState.AtHome:
                isVirtual = IsCitizenVirtual(instance, ref citizen, ShouldRealizeCitizen);
                ProcessCitizenAtHome(instance, citizenId, ref citizen, isVirtual);
                break;

            case ResidentState.MovingToTarget:
                ProcessCitizenMoving(instance, citizenId, ref citizen, true);
                break;

            case ResidentState.AtSchoolOrWork:
                isVirtual = IsCitizenVirtual(instance, ref citizen, ShouldRealizeCitizen);
                ProcessCitizenAtSchoolOrWork(instance, citizenId, ref citizen, isVirtual);
                break;

            case ResidentState.AtLunch:
            case ResidentState.Shopping:
            case ResidentState.AtLeisureArea:
            case ResidentState.Visiting:
                isVirtual = IsCitizenVirtual(instance, ref citizen, ShouldRealizeCitizen);
                ProcessCitizenVisit(instance, residentState, citizenId, ref citizen, isVirtual);
                break;

            case ResidentState.OnTour:
                ProcessCitizenOnTour(instance, citizenId, ref citizen);
                break;

            case ResidentState.Evacuating:
                ProcessCitizenEvacuation(instance, citizenId, ref citizen);
                break;

            case ResidentState.InShelter:
                isVirtual = IsCitizenVirtual(instance, ref citizen, ShouldRealizeCitizen);
                CitizenReturnsFromShelter(instance, citizenId, ref citizen, isVirtual);
                break;

            case ResidentState.Unknown:
                Log.Debug(TimeInfo.Now, $"WARNING: {GetCitizenDesc(citizenId, ref citizen, null)} is in an UNKNOWN state! Teleporting back home");
                if (CitizenProxy.GetHomeBuilding(ref citizen) != 0)
                {
                    CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home);
                }

                break;
            }
        }
Esempio n. 16
0
        private bool ProcessCitizenMoving(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen)
        {
            ushort instanceId = CitizenProxy.GetInstance(ref citizen);
            ushort vehicleId  = CitizenProxy.GetVehicle(ref citizen);

            if (instanceId == 0)
            {
                if (vehicleId == 0)
                {
                    if (CitizenProxy.GetVisitBuilding(ref citizen) != 0)
                    {
                        CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
                    }

                    if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.MovingIn))
                    {
                        CitizenMgr.ReleaseCitizen(citizenId);
                        schedule = default;
                    }
                    else
                    {
                        CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home);
                        CitizenProxy.SetArrested(ref citizen, false);
                        schedule.Schedule(ResidentState.Unknown);
                    }
                }

                return(true);
            }

            if (vehicleId == 0 && !CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating) && CitizenMgr.IsAreaEvacuating(instanceId))
            {
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} was on the way, but the area evacuates. Finding an evacuation place.");
                schedule.Schedule(ResidentState.Unknown);
                schedule.DepartureTime = default;
                TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, residentAI.GetEvacuationReason(instance, 0));
                return(true);
            }

            ushort targetBuilding = CitizenMgr.GetTargetBuilding(instanceId);
            bool   headingToWork  = targetBuilding == CitizenProxy.GetWorkBuilding(ref citizen);

            if (vehicleId != 0 && schedule.DepartureTime != default)
            {
                float maxTravelTime = headingToWork
                    ? abandonCarRideToWorkDurationThreshold
                    : abandonCarRideDurationThreshold;

                if ((TimeInfo.Now - schedule.DepartureTime).TotalHours > maxTravelTime)
                {
                    buildingAI.RegisterReachingTrouble(targetBuilding);
                    if (targetBuilding == CitizenProxy.GetHomeBuilding(ref citizen))
                    {
                        return(true);
                    }

                    Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} cancels the trip because of traffic jam");
                    schedule.Schedule(ResidentState.Relaxing);
                    schedule.Hint         = ScheduleHint.RelaxNearbyOnly;
                    schedule.CurrentState = ResidentState.InTransition;
                    return(false);
                }
            }

            if (headingToWork)
            {
                return(true);
            }

            ItemClass.Service targetService = BuildingMgr.GetBuildingService(targetBuilding);
            if (targetService == ItemClass.Service.Beautification && WeatherInfo.IsBadWeather)
            {
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} cancels the trip to a park due to bad weather");
                schedule.Schedule(ResidentState.AtHome);
                schedule.CurrentState = ResidentState.InTransition;
                return(false);
            }

            return(true);
        }
Esempio n. 17
0
        private void ProcessCitizenMoving(TAI instance, uint citizenId, ref TCitizen citizen, bool mayCancel)
        {
            ushort instanceId = CitizenProxy.GetInstance(ref citizen);
            ushort vehicleId  = CitizenProxy.GetVehicle(ref citizen);

            if (vehicleId == 0 && instanceId == 0)
            {
                if (CitizenProxy.GetVisitBuilding(ref citizen) != 0)
                {
                    CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
                }

                if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.MovingIn))
                {
                    CitizenMgr.ReleaseCitizen(citizenId);
                }
                else
                {
                    // TODO: check whether this makes sense and maybe remove/replace this logic
                    // Don't know why the original game does this...
                    CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home);
                    CitizenProxy.SetArrested(ref citizen, false);
                }

                return;
            }

            if (vehicleId == 0 && CitizenMgr.IsAreaEvacuating(instanceId) && !CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating))
            {
                Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, false)} was on the way, but the area evacuates. Finding an evacuation place.");
                TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, residentAI.GetEvacuationReason(instance, 0));
                return;
            }

            bool   returnHome     = false;
            ushort targetBuilding = CitizenMgr.GetTargetBuilding(instanceId);

            if (targetBuilding != CitizenProxy.GetWorkBuilding(ref citizen))
            {
                ItemClass.Service targetService = BuildingMgr.GetBuildingService(targetBuilding);
                if (targetService == ItemClass.Service.Beautification && IsBadWeather(citizenId))
                {
                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, false)} cancels the trip to a park due to bad weather");
                    returnHome = true;
                }
            }

            if (!returnHome && CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.WaitingTransport | CitizenInstance.Flags.WaitingTaxi))
            {
                if (mayCancel && CitizenMgr.GetInstanceWaitCounter(instanceId) == 255 && Random.ShouldOccur(AbandonTransportWaitChance))
                {
                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, false)} goes back home");
                    returnHome = true;
                }
            }

            if (returnHome)
            {
                ushort home = CitizenProxy.GetHomeBuilding(ref citizen);
                if (home == 0)
                {
                    return;
                }

                residentAI.StartMoving(instance, citizenId, ref citizen, 0, home);
            }
        }