Example #1
0
        private ushort MoveToCommercialBuilding(TAI instance, uint citizenId, ref TCitizen citizen, float distance, bool isVirtual)
        {
            ushort buildingId = CitizenProxy.GetCurrentBuilding(ref citizen);

            if (buildingId == 0)
            {
                return(0);
            }

            ushort foundBuilding = BuildingMgr.FindActiveBuilding(buildingId, distance, ItemClass.Service.Commercial);

            if (IsBuildingNoiseRestricted(foundBuilding))
            {
                Log.Debug($"Citizen {citizenId} won't go to the commercial building {foundBuilding}, it has a NIMBY policy");
                return(0);
            }

            if (StartMovingToVisitBuilding(instance, citizenId, ref citizen, foundBuilding, isVirtual))
            {
                ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen);
                uint   homeUnit     = BuildingMgr.GetCitizenUnit(homeBuilding);
                uint   citizenUnit  = CitizenProxy.GetContainingUnit(ref citizen, citizenId, homeUnit, CitizenUnit.Flags.Home);
                if (citizenUnit != 0)
                {
                    CitizenMgr.ModifyUnitGoods(citizenUnit, ShoppingGoodsAmount);
                }
            }

            return(foundBuilding);
        }
Example #2
0
        private bool CitizenReturnsHomeFromVisit(TAI instance, uint citizenId, ref TCitizen citizen, bool isVirtual)
        {
            ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen);

            if (homeBuilding == 0 || CitizenProxy.GetVehicle(ref citizen) != 0)
            {
                return(false);
            }

            ushort visitBuilding = CitizenProxy.GetVisitBuilding(ref citizen);

            switch (EventMgr.GetEventState(visitBuilding, TimeInfo.Now.AddHours(MaxHoursOnTheWay)))
            {
            case CityEventState.Upcoming:
            case CityEventState.Ongoing:
                return(false);

            case CityEventState.Finished:
                Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} returning from an event at {visitBuilding} back home to {homeBuilding}");
                ReturnFromVisit(instance, citizenId, ref citizen, homeBuilding, Citizen.Location.Home, isVirtual);
                return(true);
            }

            ItemClass.SubService visitedSubService = BuildingMgr.GetBuildingSubService(visitBuilding);
            if (Random.ShouldOccur(ReturnFromVisitChance) ||
                (visitedSubService == ItemClass.SubService.CommercialLeisure && TimeInfo.IsNightTime && BuildingMgr.IsBuildingNoiseRestricted(visitBuilding)))
            {
                Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} returning from visit back home");
                ReturnFromVisit(instance, citizenId, ref citizen, homeBuilding, Citizen.Location.Home, isVirtual);
                return(true);
            }

            return(false);
        }
Example #3
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, $"{GetCitizenDesc(citizenId, ref citizen)} is currently homeless. Cannot move home, waiting for the next opportunity");
                return;
            }

            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

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

#if DEBUG
            string logEntry = $"{GetCitizenDesc(citizenId, ref citizen)} is going from {currentBuilding} back home";
#else
            const string logEntry = null;
#endif

            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, logEntry);
            }
            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");
            }
        }
Example #4
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");
            }
        }
        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);
        }
        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 CitizenReturnsHomeFromVisit(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen);

            if (homeBuilding == 0 || CitizenProxy.GetVehicle(ref citizen) != 0)
            {
                return(false);
            }

            ushort visitBuilding = CitizenProxy.GetVisitBuilding(ref citizen);

            switch (EventMgr.GetEventState(visitBuilding, TimeInfo.Now.AddHours(MaxHoursOnTheWay)))
            {
            case CityEventState.Upcoming:
            case CityEventState.Ongoing:
                return(false);

            case CityEventState.Finished:
                Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} returning from an event at {visitBuilding} back home to {homeBuilding}");
                ReturnFromVisit(instance, citizenId, ref citizen, homeBuilding);
                return(true);
            }

            if (IsChance(ReturnFromVisitChance))
            {
                Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} returning from visit back home");
                ReturnFromVisit(instance, citizenId, ref citizen, homeBuilding);
                return(true);
            }

            return(false);
        }
Example #8
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;
            }
        }
Example #9
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)}");
        }
Example #10
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}");
        }
        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);
                }
            }
        }
Example #12
0
        private bool CitizenGoesShopping(TAI instance, uint citizenId, ref TCitizen citizen, bool isVirtual)
        {
            if (!CitizenProxy.HasFlags(ref citizen, Citizen.Flags.NeedGoods) || IsBadWeather(citizenId))
            {
                return(false);
            }

            if (TimeInfo.IsNightTime)
            {
                if (Random.ShouldOccur(GetGoOutChance(CitizenProxy.GetAge(ref citizen))))
                {
                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} wanna go shopping at night");
                    ushort localVisitPlace = MoveToCommercialBuilding(instance, citizenId, ref citizen, LocalSearchDistance, isVirtual);
                    Log.DebugIf(localVisitPlace != 0, $"Citizen {citizenId} is going shopping at night to a local shop {localVisitPlace}");
                    return(localVisitPlace > 0);
                }

                return(false);
            }

            if (Random.ShouldOccur(GoShoppingChance))
            {
                bool   localOnly       = CitizenProxy.GetWorkBuilding(ref citizen) != 0 && IsWorkDayMorning(CitizenProxy.GetAge(ref citizen));
                ushort localVisitPlace = 0;

                if (Random.ShouldOccur(Config.LocalBuildingSearchQuota))
                {
                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} wanna go shopping");
                    localVisitPlace = MoveToCommercialBuilding(instance, citizenId, ref citizen, LocalSearchDistance, isVirtual);
                    Log.DebugIf(localVisitPlace != 0, $"Citizen {citizenId} is going shopping to a local shop {localVisitPlace}");
                }

                if (localVisitPlace == 0)
                {
                    if (localOnly)
                    {
                        Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} wanna go shopping, but didn't find a local shop");
                        return(false);
                    }

                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} wanna go shopping, heading to a random shop");
                    residentAI.FindVisitPlace(instance, citizenId, CitizenProxy.GetHomeBuilding(ref citizen), residentAI.GetShoppingReason(instance));
                }

                return(true);
            }

            return(false);
        }
Example #13
0
        private void ProcessCitizenOnTour(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            if (!CitizenMgr.InstanceHasFlags(CitizenProxy.GetInstance(ref citizen), CitizenInstance.Flags.TargetIsNode))
            {
                return;
            }

            ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen);

            if (homeBuilding != 0)
            {
                Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, false)} exits a guided tour and moves back home.");
                residentAI.StartMoving(instance, citizenId, ref citizen, 0, homeBuilding);
            }
        }
Example #14
0
        private bool CitizenGoesWorking(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            ushort homeBuilding    = CitizenProxy.GetHomeBuilding(ref citizen);
            ushort workBuilding    = CitizenProxy.GetWorkBuilding(ref citizen);
            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

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

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

            residentAI.StartMoving(instance, citizenId, ref citizen, homeBuilding, workBuilding);
            return(true);
        }
        private bool CitizenGoesShopping(TAI instance, uint citizenId, ref TCitizen citizen)
        {
            if (!CitizenProxy.HasFlags(ref citizen, Citizen.Flags.NeedGoods))
            {
                return(false);
            }

            if (TimeInfo.IsNightTime)
            {
                if (IsChance(GetGoOutChance(CitizenProxy.GetAge(ref citizen))))
                {
                    ushort localVisitPlace = MoveToCommercialBuilding(instance, citizenId, ref citizen, LocalSearchDistance);
                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanna go shopping at night, trying local shop '{localVisitPlace}'");
                    return(localVisitPlace > 0);
                }

                return(false);
            }

            if (IsChance(GoShoppingChance))
            {
                bool   localOnly       = CitizenProxy.GetWorkBuilding(ref citizen) != 0 && IsWorkDayMorning(CitizenProxy.GetAge(ref citizen));
                ushort localVisitPlace = 0;

                if (IsChance(Config.LocalBuildingSearchQuota))
                {
                    localVisitPlace = MoveToCommercialBuilding(instance, citizenId, ref citizen, LocalSearchDistance);
                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanna go shopping, tries a local shop '{localVisitPlace}'");
                }

                if (localVisitPlace == 0)
                {
                    if (localOnly)
                    {
                        Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanna go shopping, but didn't find a local shop");
                        return(false);
                    }

                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanna go shopping, heading to a random shop");
                    residentAI.FindVisitPlace(instance, citizenId, CitizenProxy.GetHomeBuilding(ref citizen), residentAI.GetShoppingReason(instance));
                }

                return(true);
            }

            return(false);
        }
        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");
        }
Example #17
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);
        }
Example #18
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);
        }
Example #19
0
        private ushort MoveToCommercialBuilding(TAI instance, uint citizenId, ref TCitizen citizen, float distance)
        {
            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            if (currentBuilding == 0)
            {
                return(0);
            }

            ushort foundBuilding = BuildingMgr.FindActiveBuilding(currentBuilding, distance, ItemClass.Service.Commercial);

            if (foundBuilding == 0)
            {
                Log.Debug(LogCategory.Movement, $"Citizen {citizenId} didn't find any visitable commercial buildings nearby");
                return(0);
            }

            if (buildingAI.IsNoiseRestricted(foundBuilding, currentBuilding))
            {
                Log.Debug(LogCategory.Movement, $"Citizen {citizenId} won't go to the commercial building {foundBuilding}, it has a NIMBY policy");
                return(0);
            }

            if (StartMovingToVisitBuilding(instance, citizenId, ref citizen, foundBuilding))
            {
                ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen);
                uint   homeUnit     = BuildingMgr.GetCitizenUnit(homeBuilding);
                uint   citizenUnit  = CitizenProxy.GetContainingUnit(ref citizen, citizenId, homeUnit, CitizenUnit.Flags.Home);
                if (citizenUnit != 0)
                {
                    CitizenMgr.ModifyUnitGoods(citizenUnit, ShoppingGoodsAmount);
                }

                return(foundBuilding);
            }

            return(0);
        }
Example #20
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);
        }
Example #21
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;
            }
        }
Example #22
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);
            }
        }
Example #23
0
        private ResidentState GetResidentState(ref TCitizen citizen)
        {
            if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.DummyTraffic))
            {
                return(ResidentState.Ignored);
            }

            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            ItemClass.Service buildingService = BuildingMgr.GetBuildingService(currentBuilding);

            if (BuildingMgr.BuildingHasFlags(currentBuilding, Building.Flags.Evacuating) &&
                buildingService != ItemClass.Service.Disaster)
            {
                return(ResidentState.Evacuating);
            }

            switch (CitizenProxy.GetLocation(ref citizen))
            {
            case Citizen.Location.Home:
                return(currentBuilding != 0
                        ? ResidentState.AtHome
                        : ResidentState.Unknown);

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

                if (CitizenProxy.GetVisitBuilding(ref citizen) == currentBuilding)
                {
                    // A citizen may visit their own work building (e.g. shopping)
                    goto case Citizen.Location.Visit;
                }

                return(currentBuilding != 0
                        ? ResidentState.AtSchoolOrWork
                        : ResidentState.Unknown);

            case Citizen.Location.Visit:
                if (currentBuilding == 0)
                {
                    return(ResidentState.Unknown);
                }

                switch (buildingService)
                {
                case ItemClass.Service.Commercial:
                    if (CitizenProxy.GetWorkBuilding(ref citizen) != 0 && IsWorkDay &&
                        TimeInfo.CurrentHour > Config.LunchBegin && TimeInfo.CurrentHour < GetSpareTimeBeginHour(CitizenProxy.GetAge(ref citizen)))
                    {
                        return(ResidentState.AtLunch);
                    }

                    if (BuildingMgr.GetBuildingSubService(currentBuilding) == ItemClass.SubService.CommercialLeisure)
                    {
                        return(ResidentState.AtLeisureArea);
                    }

                    return(ResidentState.Shopping);

                case ItemClass.Service.Beautification:
                    return(ResidentState.AtLeisureArea);

                case ItemClass.Service.Disaster:
                    return(ResidentState.InShelter);
                }

                return(ResidentState.Visiting);

            case Citizen.Location.Moving:
                ushort instanceId = CitizenProxy.GetInstance(ref citizen);
                if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.OnTour | CitizenInstance.Flags.TargetIsNode, true))
                {
                    return(ResidentState.OnTour);
                }

                ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen);
                return(homeBuilding != 0 && CitizenMgr.GetTargetBuilding(instanceId) == homeBuilding
                        ? ResidentState.MovingHome
                        : ResidentState.MovingToTarget);

            default:
                return(ResidentState.Unknown);
            }
        }
Example #24
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));
                }
            }
        }
        private ResidentState GetResidentState(ref TCitizen citizen)
        {
            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            ItemClass.Service buildingService = BuildingMgr.GetBuildingService(currentBuilding);

            if (BuildingMgr.BuildingHasFlags(currentBuilding, Building.Flags.Evacuating) &&
                buildingService != ItemClass.Service.Disaster)
            {
                return(ResidentState.Evacuating);
            }

            switch (CitizenProxy.GetLocation(ref citizen))
            {
            case Citizen.Location.Home:
                if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.MovingIn))
                {
                    return(ResidentState.LeftCity);
                }

                if (currentBuilding != 0)
                {
                    return(ResidentState.AtHome);
                }

                return(ResidentState.Unknown);

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

                return(currentBuilding != 0
                        ? ResidentState.AtSchoolOrWork
                        : ResidentState.Unknown);

            case Citizen.Location.Visit:
                if (currentBuilding == 0)
                {
                    return(ResidentState.Unknown);
                }

                switch (buildingService)
                {
                case ItemClass.Service.Commercial:
                    if (CitizenProxy.GetWorkBuilding(ref citizen) != 0 && IsWorkDay &&
                        TimeInfo.CurrentHour > Config.LunchBegin && TimeInfo.CurrentHour < GetSpareTimeBeginHour(CitizenProxy.GetAge(ref citizen)))
                    {
                        return(ResidentState.AtLunch);
                    }

                    if (BuildingMgr.GetBuildingSubService(currentBuilding) == ItemClass.SubService.CommercialLeisure)
                    {
                        return(ResidentState.AtLeisureArea);
                    }

                    return(ResidentState.Shopping);

                case ItemClass.Service.Beautification:
                    return(ResidentState.AtLeisureArea);

                case ItemClass.Service.Disaster:
                    return(ResidentState.InShelter);
                }

                return(ResidentState.Visiting);

            case Citizen.Location.Moving:
                ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen);
                return(homeBuilding != 0 && CitizenMgr.GetTargetBuilding(CitizenProxy.GetInstance(ref citizen)) == homeBuilding
                        ? ResidentState.MovingHome
                        : ResidentState.MovingToTarget);

            default:
                return(ResidentState.Unknown);
            }
        }