Esempio n. 1
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) || CitizenProxy.IsSick(ref citizen))
            {
                CitizenMgr.ReleaseCitizen(citizenId);
                return;
            }

            switch (CitizenProxy.GetLocation(ref citizen))
            {
            case Citizen.Location.Home:
            case Citizen.Location.Work:
                CitizenMgr.ReleaseCitizen(citizenId);
                break;

            case Citizen.Location.Visit:
                ProcessVisit(instance, citizenId, ref citizen);
                break;

            case Citizen.Location.Moving:
                ProcessMoving(instance, citizenId, ref citizen);
                break;
            }
        }
Esempio n. 2
0
        private void ProcessMoving(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)
                {
                    CitizenMgr.ReleaseCitizen(citizenId);
                }

                return;
            }

            if (vehicleId == 0 && CitizenMgr.IsAreaEvacuating(instanceId) && !CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating))
            {
                Log.Debug(TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} was on the way, but the area evacuates. Leaving the city.");
                touristAI.FindVisitPlace(instance, citizenId, CitizenProxy.GetCurrentBuilding(ref citizen), touristAI.GetLeavingReason(instance, citizenId, ref citizen));
                return;
            }

            if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.TargetIsNode | CitizenInstance.Flags.OnTour, true))
            {
                FindRandomVisitPlace(instance, citizenId, ref citizen, TouristDoNothingProbability, 0);
            }
        }
        private void ProcessCitizenAtHome(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            if (CitizenProxy.GetHomeBuilding(ref citizen) == 0)
            {
                Log.Debug($"WARNING: {GetCitizenDesc(citizenId, ref citizen)} is in corrupt state: at home with no home building. Releasing the poor citizen.");
                CitizenMgr.ReleaseCitizen(citizenId);
                return;
            }

            ushort vehicle = CitizenProxy.GetVehicle(ref citizen);

            if (vehicle != 0)
            {
                Log.Debug(TimeInfo.Now, $"WARNING: {GetCitizenDesc(citizenId, ref citizen)} is at home but vehicle = {vehicle}");
                return;
            }

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

            if (IsBusyAtHomeInTheMorning(CitizenProxy.GetAge(ref citizen)) || !residentAI.DoRandomMove(instance))
            {
                return;
            }

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

            CitizenGoesRelaxing(instance, citizenId, ref citizen);
        }
        private bool CitzenReturnsFromShelter(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            ushort visitBuilding = CitizenProxy.GetVisitBuilding(ref citizen);

            if (BuildingMgr.GetBuildingService(visitBuilding) != ItemClass.Service.Disaster)
            {
                return(true);
            }

            if (!BuildingMgr.BuildingHasFlags(visitBuilding, Building.Flags.Downgrading))
            {
                return(false);
            }

            ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen);

            if (homeBuilding == 0)
            {
                Log.Debug($"WARNING: {GetCitizenDesc(citizenId, ref citizen)} was in a shelter but seems to be homeless. Releasing the citizen.");
                CitizenMgr.ReleaseCitizen(citizenId);
                return(true);
            }

            Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} returning from evacuation place back home");
            ReturnFromVisit(instance, citizenId, ref citizen, homeBuilding);
            return(true);
        }
Esempio n. 5
0
        private void DoScheduledHome(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen)
        {
            ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen);

            if (homeBuilding == 0)
            {
                Log.Debug(LogCategory.State, $"WARNING: {GetCitizenDesc(citizenId, ref citizen)} is in corrupt state: want to go home with no home building. Releasing the poor citizen.");
                CitizenMgr.ReleaseCitizen(citizenId);
                schedule = default;
                return;
            }

            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

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

            if (residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, homeBuilding))
            {
                CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0);
                schedule.Schedule(ResidentState.Unknown);
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is going from {currentBuilding} back home");
            }
            else
            {
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted to go home from {currentBuilding} but can't, waiting for the next opportunity");
            }
        }
Esempio n. 6
0
        private void ProcessVisit(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            ushort visitBuilding = CitizenProxy.GetVisitBuilding(ref citizen);

            if (visitBuilding == 0)
            {
                CitizenMgr.ReleaseCitizen(citizenId);
                return;
            }

            if (BuildingMgr.BuildingHasFlags(visitBuilding, Building.Flags.Evacuating))
            {
                touristAI.FindEvacuationPlace(instance, citizenId, visitBuilding, touristAI.GetEvacuationReason(instance, visitBuilding));
                return;
            }

            switch (BuildingMgr.GetBuildingService(visitBuilding))
            {
            case ItemClass.Service.Disaster:
                if (BuildingMgr.BuildingHasFlags(visitBuilding, Building.Flags.Downgrading))
                {
                    CitizenProxy.RemoveFlags(ref citizen, Citizen.Flags.Evacuating);
                    FindRandomVisitPlace(instance, citizenId, ref citizen, 0, visitBuilding);
                }

                return;

            // Tourist is sleeping in a hotel
            case ItemClass.Service.Commercial
                when BuildingMgr.GetBuildingSubService(visitBuilding) == ItemClass.SubService.CommercialTourist &&
                !Random.ShouldOccur(GetHotelLeaveChance()):
                return;
            }

            ICityEvent currentEvent = EventMgr.GetCityEvent(visitBuilding);

            if (currentEvent != null && currentEvent.StartTime < TimeInfo.Now)
            {
                if (Random.ShouldOccur(TouristShoppingChance))
                {
                    BuildingMgr.ModifyMaterialBuffer(visitBuilding, TransferManager.TransferReason.Shopping, -ShoppingGoodsAmount);
                }

                return;
            }

            if (Random.ShouldOccur(TouristEventChance) && !WeatherInfo.IsBadWeather)
            {
                ICityEvent cityEvent = GetUpcomingEventToAttend(citizenId, ref citizen);
                if (cityEvent != null &&
                    StartMovingToVisitBuilding(instance, citizenId, ref citizen, CitizenProxy.GetCurrentBuilding(ref citizen), cityEvent.BuildingId))
                {
                    Log.Debug(LogCategory.Events, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} attending an event at {cityEvent.BuildingId}");
                    return;
                }
            }

            FindRandomVisitPlace(instance, citizenId, ref citizen, 0, visitBuilding);
        }
Esempio n. 7
0
        /// <summary>
        /// The main 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 <see cref="Citizen"/> reference to process.</param>
        public void UpdateLocation(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            if (!EnsureCitizenValid(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);

            switch (residentState)
            {
            case ResidentState.LeftCity:
                CitizenMgr.ReleaseCitizen(citizenId);
                break;

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

            case ResidentState.AtHome:
                ProcessCitizenAtHome(instance, citizenId, ref citizen);
                break;

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

            case ResidentState.AtSchoolOrWork:
                ProcessCitizenAtSchoolOrWork(instance, citizenId, ref citizen);
                break;

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

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

            case ResidentState.InShelter:
                CitzenReturnsFromShelter(instance, citizenId, ref citizen);
                return;
            }
        }
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);
        }
Esempio n. 9
0
        /// <summary>
        /// Ensures that the specified citizen is in a valid state and can be processed.
        /// </summary>
        ///
        /// <param name="citizenId">The citizen ID to check.</param>
        /// <param name="citizen">The citizen data reference.</param>
        ///
        /// <returns><c>true</c> if the specified citizen is in a valid state; otherwise, <c>false</c>.</returns>
        protected bool EnsureCitizenCanBeProcessed(uint citizenId, ref TCitizen citizen)
        {
            if (CitizenProxy.IsEmpty(ref citizen) ||
                CitizenProxy.HasFlags(ref citizen, Citizen.Flags.MovingIn) && CitizenProxy.GetLocation(ref citizen) == Citizen.Location.Home)
            {
                CitizenMgr.ReleaseCitizen(citizenId);
                return(false);
            }

            if (CitizenProxy.IsCollapsed(ref citizen))
            {
                Log.Debug(LogCategory.State, $"{GetCitizenDesc(citizenId, ref citizen)} is collapsed, doing nothing...");
                return(false);
            }

            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);
            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");
        }
        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");
        }
Esempio n. 12
0
        protected bool EnsureCitizenValid(uint citizenId, ref TCitizen citizen)
        {
            if (CitizenProxy.GetHomeBuilding(ref citizen) == 0 &&
                CitizenProxy.GetWorkBuilding(ref citizen) == 0 &&
                CitizenProxy.GetVisitBuilding(ref citizen) == 0 &&
                CitizenProxy.GetInstance(ref citizen) == 0 &&
                CitizenProxy.GetVehicle(ref citizen) == 0)
            {
                CitizenMgr.ReleaseCitizen(citizenId);
                return(false);
            }

            if (CitizenProxy.IsCollapsed(ref citizen))
            {
                Log.Debug($"{GetCitizenDesc(citizenId, ref citizen)} is collapsed, doing nothing...");
                return(false);
            }

            return(true);
        }
Esempio n. 13
0
        /// <summary>
        /// Ensures that the provided citizen is in a valid state and can be processed.
        /// </summary>
        ///
        /// <param name="citizenId">The citizen ID to check.</param>
        /// <param name="citizen">The citizen data reference.</param>
        ///
        /// <returns><c>true</c> if the provided citizen is in a valid state; otherwise, <c>false</c>.</returns>
        protected bool EnsureCitizenCanBeProcessed(uint citizenId, ref TCitizen citizen)
        {
            if ((CitizenProxy.GetHomeBuilding(ref citizen) == 0 &&
                 CitizenProxy.GetWorkBuilding(ref citizen) == 0 &&
                 CitizenProxy.GetVisitBuilding(ref citizen) == 0 &&
                 CitizenProxy.GetInstance(ref citizen) == 0 &&
                 CitizenProxy.GetVehicle(ref citizen) == 0)
                ||
                (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.MovingIn) && CitizenProxy.GetLocation(ref citizen) == Citizen.Location.Home))
            {
                CitizenMgr.ReleaseCitizen(citizenId);
                return(false);
            }

            if (CitizenProxy.IsCollapsed(ref citizen))
            {
                Log.Debug($"{GetCitizenDesc(citizenId, ref citizen, false)} is collapsed, doing nothing...");
                return(false);
            }

            return(true);
        }
Esempio n. 14
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);
            }
        }
Esempio n. 15
0
        private void ProcessVisit(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            ushort visitBuilding = CitizenProxy.GetVisitBuilding(ref citizen);

            if (visitBuilding == 0)
            {
                CitizenMgr.ReleaseCitizen(citizenId);
                return;
            }

            if (BuildingMgr.BuildingHasFlags(visitBuilding, Building.Flags.Evacuating))
            {
                touristAI.FindEvacuationPlace(instance, citizenId, visitBuilding, touristAI.GetEvacuationReason(instance, visitBuilding));
                return;
            }

            switch (BuildingMgr.GetBuildingService(visitBuilding))
            {
            case ItemClass.Service.Disaster:
                if (BuildingMgr.BuildingHasFlags(visitBuilding, Building.Flags.Downgrading))
                {
                    FindRandomVisitPlace(instance, citizenId, ref citizen, 0, visitBuilding);
                }

                return;

            // Tourist is sleeping in a hotel
            case ItemClass.Service.Commercial
                when TimeInfo.IsNightTime && BuildingMgr.GetBuildingSubService(visitBuilding) == ItemClass.SubService.CommercialTourist:
                return;
            }

            if (Random.ShouldOccur(TouristEventChance) && !IsBadWeather())
            {
                ICityEvent cityEvent = GetUpcomingEventToAttend(citizenId, ref citizen);
                if (cityEvent != null)
                {
                    StartMovingToVisitBuilding(instance, citizenId, ref citizen, CitizenProxy.GetCurrentBuilding(ref citizen), cityEvent.BuildingId);
                    Log.Debug(TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} attending an event at {cityEvent.BuildingId}");
                    return;
                }
            }

            int doNothingChance;

            switch (EventMgr.GetEventState(visitBuilding, DateTime.MaxValue))
            {
            case CityEventState.Ongoing:
                if (Random.ShouldOccur(TouristShoppingChance))
                {
                    BuildingMgr.ModifyMaterialBuffer(visitBuilding, TransferManager.TransferReason.Shopping, -ShoppingGoodsAmount);
                }

                return;

            case CityEventState.Finished:
                doNothingChance = 0;
                break;

            default:
                doNothingChance = TouristDoNothingProbability;
                break;
            }

            FindRandomVisitPlace(instance, citizenId, ref citizen, doNothingChance, visitBuilding);
        }
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 ProcessMoving(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)
                {
                    CitizenMgr.ReleaseCitizen(citizenId);
                }

                return;
            }

            bool isEvacuating = CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating);

            if (vehicleId == 0 && !isEvacuating && CitizenMgr.IsAreaEvacuating(instanceId))
            {
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} was on the way, but the area evacuates. Searching for a shelter.");
                TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, touristAI.GetEvacuationReason(instance, 0));
                return;
            }

            if (isEvacuating)
            {
                return;
            }

            if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.TargetIsNode | CitizenInstance.Flags.OnTour, all: true))
            {
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} exits the guided tour.");
                FindRandomVisitPlace(instance, citizenId, ref citizen, TouristDoNothingProbability, 0);
                return;
            }

            ushort targetBuildingId = CitizenProxy.GetVisitBuilding(ref citizen);

            TouristTarget target;

            if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.TargetIsNode))
            {
                if (CitizenMgr.GetTargetNode(instanceId) != 0)
                {
                    target = TouristTarget.Relaxing;
                }
                else
                {
                    return;
                }
            }
            else
            {
                if (targetBuildingId == 0)
                {
                    targetBuildingId = CitizenMgr.GetTargetBuilding(instanceId);
                }

                BuildingMgr.GetBuildingService(targetBuildingId, out ItemClass.Service targetService, out ItemClass.SubService targetSubService);
                switch (targetService)
                {
                // Heading to a hotel, no need to change anything
                case ItemClass.Service.Commercial when targetSubService == ItemClass.SubService.CommercialTourist:
                    return;

                case ItemClass.Service.Commercial when targetSubService == ItemClass.SubService.CommercialLeisure:
                    target = TouristTarget.Party;
                    break;

                case ItemClass.Service.Tourism:
                case ItemClass.Service.Beautification:
                case ItemClass.Service.Monument:
                    target = TouristTarget.Relaxing;
                    break;

                case ItemClass.Service.Commercial:
                    target = TouristTarget.Shopping;
                    break;

                default:
                    return;
                }
            }

            if (GetTouristGoingOutChance(ref citizen, target) > 0)
            {
                return;
            }

            ushort hotel = FindHotel(targetBuildingId);

            if (hotel != 0)
            {
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} changes the target and moves to a hotel {hotel} because of time or weather");
                StartMovingToVisitBuilding(instance, citizenId, ref citizen, 0, hotel);
            }
            else
            {
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} leaves the city because of time or weather");
                touristAI.FindVisitPlace(instance, citizenId, 0, touristAI.GetLeavingReason(instance, citizenId, ref citizen));
            }
        }
Esempio n. 18
0
        private void ProcessVisit(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            ushort visitBuilding = CitizenProxy.GetVisitBuilding(ref citizen);

            if (visitBuilding == 0)
            {
                CitizenMgr.ReleaseCitizen(citizenId);
                return;
            }

            if (BuildingMgr.BuildingHasFlags(visitBuilding, Building.Flags.Evacuating))
            {
                touristAI.FindEvacuationPlace(instance, citizenId, visitBuilding, touristAI.GetEvacuationReason(instance, visitBuilding));
                return;
            }

            switch (BuildingMgr.GetBuildingService(visitBuilding))
            {
            case ItemClass.Service.Disaster:
                if (BuildingMgr.BuildingHasFlags(visitBuilding, Building.Flags.Downgrading))
                {
                    FindRandomVisitPlace(instance, citizenId, ref citizen, 0, visitBuilding);
                }

                return;

            // Tourist is sleeping in a hotel
            case ItemClass.Service.Commercial
                when TimeInfo.IsNightTime && BuildingMgr.GetBuildingSubService(visitBuilding) == ItemClass.SubService.CommercialTourist:
                return;
            }

            if (IsChance(TouristEventChance) && AttendUpcomingEvent(citizenId, ref citizen, out ushort eventBuilding))
            {
                StartMovingToVisitBuilding(instance, citizenId, ref citizen, CitizenProxy.GetCurrentBuilding(ref citizen), eventBuilding);
                touristAI.AddTouristVisit(instance, citizenId, eventBuilding);
                Log.Debug(TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} attending an event at {eventBuilding}");
                return;
            }

            bool doShopping;

            switch (EventMgr.GetEventState(visitBuilding, DateTime.MaxValue))
            {
            case CityEventState.Ongoing:
                doShopping = IsChance(TouristShoppingChance);
                break;

            case CityEventState.Finished:
                doShopping = !FindRandomVisitPlace(instance, citizenId, ref citizen, 0, visitBuilding);
                break;

            default:
                doShopping = false;
                break;
            }

            if (doShopping || !FindRandomVisitPlace(instance, citizenId, ref citizen, TouristDoNothingProbability, visitBuilding))
            {
                BuildingMgr.ModifyMaterialBuffer(visitBuilding, TransferManager.TransferReason.Shopping, -ShoppingGoodsAmount);
                touristAI.AddTouristVisit(instance, citizenId, visitBuilding);
            }
        }