private bool IsBuildingNoiseRestricted(ushort targetBuilding, ushort currentBuilding)
        {
            if (BuildingMgr.GetBuildingSubService(targetBuilding) != ItemClass.SubService.CommercialLeisure)
            {
                return(false);
            }

            float currentHour = TimeInfo.CurrentHour;

            if (currentHour >= Config.GoToSleepUpHour || currentHour <= Config.WakeupHour)
            {
                return(BuildingMgr.IsBuildingNoiseRestricted(targetBuilding));
            }

            float travelTime = GetEstimatedTravelTime(currentBuilding, targetBuilding);

            if (travelTime == 0)
            {
                return(false);
            }

            float arriveHour = (float)TimeInfo.Now.AddHours(travelTime).TimeOfDay.TotalHours;

            if (arriveHour >= Config.GoToSleepUpHour || arriveHour <= Config.WakeupHour)
            {
                return(BuildingMgr.IsBuildingNoiseRestricted(targetBuilding));
            }

            return(false);
        }
示例#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);
        }
示例#3
0
        private uint AdjustRelaxChance(uint relaxChance, ref TCitizen citizen)
        {
            ushort visitBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            return((BuildingMgr.GetBuildingSubService(visitBuilding) == ItemClass.SubService.BeautificationParks)
                ? relaxChance * 2
                : relaxChance);
        }
示例#4
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;
            }
        }
示例#5
0
        private bool ProcessCitizenRelaxing(ref CitizenSchedule schedule, uint citizenId, ref TCitizen citizen)
        {
            ushort currentBuilding = CitizenProxy.GetVisitBuilding(ref citizen);

            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(currentBuilding, TransferManager.TransferReason.Shopping, -ShoppingGoodsAmount);
            }

            return(RescheduleVisit(ref schedule, citizenId, ref citizen, currentBuilding));
        }
        private uint AdjustRelaxChance(uint relaxChance, ref TCitizen citizen)
        {
            ushort visitBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            if (BuildingMgr.GetBuildingSubService(visitBuilding) == ItemClass.SubService.BeautificationParks)
            {
                return(relaxChance * 2);
            }
            else if (CitizenProxy.GetAge(ref citizen) == Citizen.AgeGroup.Senior &&
                     BuildingMgr.IsBuildingServiceLevel(visitBuilding, ItemClass.Service.HealthCare, ItemClass.Level.Level3))
            {
                return(relaxChance * 4);
            }
            else
            {
                return(relaxChance);
            }
        }
示例#7
0
        private bool ShouldMoveToSchoolOrWork(uint citizenId, ushort workBuilding, ushort currentBuilding, Citizen.AgeGroup citizenAge)
        {
            if (workBuilding == 0 || citizenAge == Citizen.AgeGroup.Senior)
            {
                return(false);
            }

            ItemClass.Service    buildingSevice     = BuildingMgr.GetBuildingService(workBuilding);
            ItemClass.SubService buildingSubService = BuildingMgr.GetBuildingSubService(workBuilding);

            if (IsWeekend && !IsBuildingActiveOnWeekend(buildingSevice, buildingSubService))
            {
                return(false);
            }

            if ((citizenId & 0x7FF) == TimeInfo.Now.Day)
            {
                Log.Debug(TimeInfo.Now, $"Citizen {citizenId} has a day off work today");
                return(false);
            }

            if (citizenAge == Citizen.AgeGroup.Child || citizenAge == Citizen.AgeGroup.Teen)
            {
                return(ShouldMoveToSchoolOrWork(currentBuilding, workBuilding, Config.SchoolBegin, Config.SchoolEnd, 0));
            }

            GetWorkShiftTimes(citizenId, buildingSevice, buildingSubService, out float workBeginHour, out float workEndHour);
            if (!CheckMinimumShiftDuration(workBeginHour, workEndHour))
            {
                return(false);
            }

            float overtime = Random.ShouldOccur(Config.OnTimeQuota) ? 0 : Config.MaxOvertime * Random.GetRandomValue(100u) / 200f;

            return(ShouldMoveToSchoolOrWork(currentBuilding, workBuilding, workBeginHour, workEndHour, overtime));
        }
示例#8
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);
        }
示例#9
0
        private bool ShouldReturnFromSchoolOrWork(uint citizenId, ushort buildingId, Citizen.AgeGroup citizenAge)
        {
            if (citizenAge == Citizen.AgeGroup.Senior)
            {
                return(true);
            }

            ItemClass.Service    buildingSevice     = BuildingMgr.GetBuildingService(buildingId);
            ItemClass.SubService buildingSubService = BuildingMgr.GetBuildingSubService(buildingId);

            if (IsWeekend && !IsBuildingActiveOnWeekend(buildingSevice, buildingSubService))
            {
                return(true);
            }

            float currentHour = TimeInfo.CurrentHour;

            if (citizenAge == Citizen.AgeGroup.Child || citizenAge == Citizen.AgeGroup.Teen)
            {
                return(currentHour >= Config.SchoolEnd || currentHour < Config.SchoolBegin - MaxHoursOnTheWay);
            }

            GetWorkShiftTimes(citizenId, buildingSevice, buildingSubService, out float workBeginHour, out float workEndHour);
            if (!CheckMinimumShiftDuration(workBeginHour, workEndHour))
            {
                return(true);
            }

            float earliestGotoHour = workBeginHour - MaxHoursOnTheWay - Config.MaxOvertime;

            if (earliestGotoHour < 0)
            {
                earliestGotoHour += 24f;
            }

            float latestLeaveHour = workEndHour + Config.MaxOvertime;

            if (latestLeaveHour >= 24f)
            {
                latestLeaveHour -= 24f;
            }

            if (earliestGotoHour < latestLeaveHour)
            {
                if (currentHour >= latestLeaveHour || currentHour < earliestGotoHour)
                {
                    return(true);
                }
                else if (currentHour >= workEndHour)
                {
                    return(Random.ShouldOccur(Config.OnTimeQuota));
                }
            }
            else
            {
                if (currentHour >= latestLeaveHour && currentHour < earliestGotoHour)
                {
                    return(true);
                }
                else if (currentHour >= workEndHour && currentHour < earliestGotoHour)
                {
                    return(Random.ShouldOccur(Config.OnTimeQuota));
                }
            }

            return(false);
        }
示例#10
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);
            }
        }
示例#11
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);
            }
        }
        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);
            }
        }