示例#1
0
        private void DisplayCityEvent(ICityEvent cityEvent, DateTime todayStart, DateTime todayEnd)
        {
            float startPercent = cityEvent.StartTime <= todayStart
                ? 0
                : (float)cityEvent.StartTime.TimeOfDay.TotalHours / 24f;

            float endPercent = cityEvent.EndTime >= todayEnd
                ? 1f
                : (float)cityEvent.EndTime.TimeOfDay.TotalHours / 24f;

            float startPosition = progressSprite.width * startPercent;
            float endPosition   = progressSprite.width * endPercent;

            UISprite eventSprite = progressSprite.AddUIComponent <UISprite>();

            eventSprite.name             = UISpriteEvent + cityEvent.BuildingId;
            eventSprite.relativePosition = new Vector3(startPosition, 0);
            eventSprite.atlas            = progressSprite.atlas;
            eventSprite.spriteName       = progressSprite.spriteName;
            eventSprite.height           = progressSprite.height;
            eventSprite.width            = endPosition - startPosition;
            eventSprite.fillDirection    = UIFillDirection.Horizontal;
            eventSprite.color            = EventColor;
            eventSprite.fillAmount       = 1f;
            eventSprite.objectUserData   = cityEvent;
            eventSprite.eventClicked    += EventSprite_Clicked;
            SetEventTooltip(eventSprite, todayStart, todayEnd);
        }
示例#2
0
        /// <summary>Reads the data set from the specified <see cref="Stream"/>.</summary>
        /// <param name="source">A <see cref="Stream"/> to read the data set from.</param>
        void IStorageData.ReadData(Stream source)
        {
            lastActiveEvent = null;
            activeEvent     = null;
            upcomingEvents.Clear();

            var serializer = new XmlSerializer(typeof(RealTimeEventStorageContainer));
            var data       = (RealTimeEventStorageContainer)serializer.Deserialize(source);

            earliestEvent = new DateTime(data.EarliestEvent);

            foreach (RealTimeEventStorage storedEvent in data.Events)
            {
                if (string.IsNullOrEmpty(storedEvent.EventName) || string.IsNullOrEmpty(storedEvent.BuildingClassName))
                {
                    continue;
                }

                CityEventTemplate template = eventProvider.GetEventTemplate(storedEvent.EventName, storedEvent.BuildingClassName);
                var realTimeEvent          = new RealTimeCityEvent(template, storedEvent.AttendeesCount);
                realTimeEvent.Configure(storedEvent.BuildingId, storedEvent.BuildingName, new DateTime(storedEvent.StartTime));

                if (realTimeEvent.EndTime < timeInfo.Now)
                {
                    lastActiveEvent = realTimeEvent;
                }
                else
                {
                    upcomingEvents.AddLast(realTimeEvent);
                }
            }

            OnEventsChanged();
        }
        private bool ScheduleRelaxing(ref CitizenSchedule schedule, uint citizenId, ref TCitizen citizen)
        {
            Citizen.AgeGroup citizenAge = CitizenProxy.GetAge(ref citizen);
            if (!Random.ShouldOccur(spareTimeBehavior.GetGoOutChance(citizenAge)) || IsBadWeather())
            {
                return(false);
            }

            ICityEvent cityEvent = GetUpcomingEventToAttend(citizenId, ref citizen);

            if (cityEvent != null)
            {
                ushort   currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);
                DateTime departureTime   = cityEvent.StartTime.AddHours(-GetEstimatedTravelTime(currentBuilding, cityEvent.BuildingId));
                schedule.Schedule(ResidentState.Relaxing, departureTime);
                schedule.EventBuilding = cityEvent.BuildingId;
                schedule.Hint          = ScheduleHint.AttendingEvent;
                return(true);
            }

            schedule.Schedule(ResidentState.Relaxing, default);
            schedule.Hint = TimeInfo.IsNightTime
                ? ScheduleHint.RelaxAtLeisureBuilding
                : ScheduleHint.None;

            return(true);
        }
示例#4
0
        private void Update()
        {
            if (activeEvent != null && activeEvent.EndTime <= timeInfo.Now)
            {
                Log.Debug(LogCategory.Events, timeInfo.Now, $"Event finished in {activeEvent.BuildingId}, started at {activeEvent.StartTime}, end time {activeEvent.EndTime}");
                lastActiveEvent = activeEvent;
                activeEvent     = null;
            }

            bool eventsChanged = SynchronizeWithVanillaEvents();

            if (upcomingEvents.Count != 0)
            {
                LinkedListNode <ICityEvent> upcomingEvent = upcomingEvents.First;
                while (upcomingEvent != null && upcomingEvent.Value.StartTime <= timeInfo.Now)
                {
                    if (activeEvent != null)
                    {
                        lastActiveEvent = activeEvent;
                    }

                    activeEvent = upcomingEvent.Value;
                    upcomingEvents.RemoveFirst();
                    eventsChanged = true;
                    upcomingEvent = upcomingEvent.Next;
                    Log.Debug(LogCategory.Events, timeInfo.Now, $"Event started! Building {activeEvent.BuildingId}, ends on {activeEvent.EndTime}");
                }
            }

            if (eventsChanged)
            {
                OnEventsChanged();
            }
        }
示例#5
0
        private void CreateRandomEvent(ushort buildingId)
        {
            string buildingClass = buildingManager.GetBuildingClassName(buildingId);

            if (string.IsNullOrEmpty(buildingClass))
            {
                return;
            }

            ICityEvent newEvent = eventProvider.GetRandomEvent(buildingClass);

            if (newEvent == null)
            {
                return;
            }

            DateTime startTime = upcomingEvents.Count == 0
                ? timeInfo.Now
                : upcomingEvents.Last.Value.EndTime.Add(MinimumIntervalBetweenEvents);

            startTime = AdjustEventStartTime(startTime, randomize: true);
            if (startTime < earliestEvent)
            {
                return;
            }

            earliestEvent = startTime.AddHours(randomizer.GetRandomValue(EventIntervalVariance));

            newEvent.Configure(buildingId, buildingManager.GetBuildingName(buildingId), startTime);
            upcomingEvents.AddLast(newEvent);
            OnEventsChanged();
            Log.Debug(LogCategory.Events, timeInfo.Now, $"New event created for building {newEvent.BuildingId}, starts on {newEvent.StartTime}, ends on {newEvent.EndTime}");
        }
示例#6
0
        private bool ScheduleRelaxing(ref CitizenSchedule schedule, uint citizenId, ref TCitizen citizen)
        {
            Citizen.AgeGroup citizenAge = CitizenProxy.GetAge(ref citizen);

            uint relaxChance = spareTimeBehavior.GetRelaxingChance(citizenAge, schedule.WorkShift, schedule.WorkStatus == WorkStatus.OnVacation);

            relaxChance = AdjustRelaxChance(relaxChance, ref citizen);

            if (!Random.ShouldOccur(relaxChance) || WeatherInfo.IsBadWeather)
            {
                return(false);
            }

            ICityEvent cityEvent = GetUpcomingEventToAttend(citizenId, ref citizen);

            if (cityEvent != null)
            {
                ushort   currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);
                DateTime departureTime   = cityEvent.StartTime.AddHours(-travelBehavior.GetEstimatedTravelTime(currentBuilding, cityEvent.BuildingId));
                schedule.Schedule(ResidentState.Relaxing, departureTime);
                schedule.EventBuilding = cityEvent.BuildingId;
                schedule.Hint          = ScheduleHint.AttendingEvent;
                return(true);
            }

            schedule.Schedule(ResidentState.Relaxing);
            schedule.Hint = TimeInfo.IsNightTime && Random.ShouldOccur(NightLeisureChance)
                ? ScheduleHint.RelaxAtLeisureBuilding
                : ScheduleHint.None;

            return(true);
        }
示例#7
0
        private void CreateRandomEvent(ushort buildingId)
        {
            string buildingClass = buildingManager.GetBuildingClassName(buildingId);

            if (string.IsNullOrEmpty(buildingClass))
            {
                return;
            }

            ICityEvent newEvent = eventProvider.GetRandomEvent(buildingClass);

            if (newEvent == null)
            {
                return;
            }

            DateTime startTime = GetRandomEventStartTime();

            if (startTime < earliestEvent)
            {
                return;
            }

            earliestEvent = startTime.AddHours(simulationManager.GetRandomizer().Int32(EventIntervalVariance));

            newEvent.Configure(buildingId, buildingManager.GetBuildingName(buildingId), startTime);
            upcomingEvents.AddLast(newEvent);
            OnEventsChanged();
            Log.Debug(timeInfo.Now, $"New event created for building {newEvent.BuildingId}, starts on {newEvent.StartTime}, ends on {newEvent.EndTime}");
        }
示例#8
0
        private bool MustCancelEvent(ICityEvent cityEvent)
        {
            Building.Flags flags = Building.Flags.Abandoned | Building.Flags.BurnedDown | Building.Flags.Collapsed
                                   | Building.Flags.Deleted | Building.Flags.Demolishing | Building.Flags.Evacuating | Building.Flags.Flooded;

            return(buildingManager.BuildingHasFlags(cityEvent.BuildingId, flags, true));
        }
示例#9
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);
        }
示例#10
0
        private void Update()
        {
            if (activeEvent != null && activeEvent.EndTime <= timeInfo.Now)
            {
                Log.Debug(timeInfo.Now, $"Event finished in {activeEvent.BuildingId}, started at {activeEvent.StartTime}, end time {activeEvent.EndTime}");
                lastActiveEvent = activeEvent;
                activeEvent     = null;
            }

            bool eventsChanged = false;

            foreach (ushort eventId in eventManager.GetUpcomingEvents(timeInfo.Now, timeInfo.Now.AddDays(1)))
            {
                eventManager.TryGetEventInfo(eventId, out ushort buildingId, out DateTime startTime, out float duration, out float ticketPrice);

                if (upcomingEvents.Concat(new[] { activeEvent })
                    .OfType <VanillaEvent>()
                    .Any(e => e.BuildingId == buildingId && e.StartTime == startTime))
                {
                    continue;
                }

                var newEvent = new VanillaEvent(duration, ticketPrice);
                newEvent.Configure(buildingId, buildingManager.GetBuildingName(buildingId), startTime);
                eventsChanged = true;
                Log.Debug(timeInfo.Now, $"Vanilla event registered for {newEvent.BuildingId}, start time {newEvent.StartTime}, end time {newEvent.EndTime}");

                LinkedListNode <ICityEvent> existingEvent = upcomingEvents.FirstOrDefaultNode(e => e.StartTime > startTime);
                if (existingEvent == null)
                {
                    upcomingEvents.AddLast(newEvent);
                }
                else
                {
                    upcomingEvents.AddBefore(existingEvent, newEvent);
                }
            }

            if (upcomingEvents.Count == 0)
            {
                return;
            }

            ICityEvent upcomingEvent = upcomingEvents.First.Value;

            if (upcomingEvent.StartTime <= timeInfo.Now)
            {
                activeEvent = upcomingEvent;
                upcomingEvents.RemoveFirst();
                eventsChanged = true;
                Log.Debug(timeInfo.Now, $"Event started! Building {activeEvent.BuildingId}, ends on {activeEvent.EndTime}");
            }

            if (eventsChanged)
            {
                OnEventsChanged();
            }
        }
示例#11
0
        private bool CanAttendEvent(uint citizenId, ref TCitizen citizen, ICityEvent cityEvent)
        {
            Citizen.AgeGroup  age       = CitizenProxy.GetAge(ref citizen);
            Citizen.Gender    gender    = CitizenProxy.GetGender(citizenId);
            Citizen.Education education = CitizenProxy.GetEducationLevel(ref citizen);
            Citizen.Wealth    wealth    = CitizenProxy.GetWealthLevel(ref citizen);
            Citizen.Wellbeing wellbeing = CitizenProxy.GetWellbeingLevel(ref citizen);
            Citizen.Happiness happiness = CitizenProxy.GetHappinessLevel(ref citizen);

            return(cityEvent.TryAcceptAttendee(age, gender, education, wealth, wellbeing, happiness, Random));
        }
        private void DoScheduledRelaxing(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen)
        {
            ushort buildingId = CitizenProxy.GetCurrentBuilding(ref citizen);

            switch (schedule.Hint)
            {
            case ScheduleHint.RelaxAtLeisureBuilding:
                schedule.Schedule(ResidentState.Unknown, default);

                ushort leisure = MoveToLeisureBuilding(instance, citizenId, ref citizen, buildingId);
                if (leisure == 0)
                {
                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted relax but didn't found a leisure building");
                }
                else
                {
                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} heading to a leisure building {leisure}");
                }

                return;

            case ScheduleHint.AttendingEvent:
                DateTime   returnTime = default;
                ICityEvent cityEvent  = EventMgr.GetCityEvent(schedule.EventBuilding);
                if (cityEvent == null)
                {
                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted attend an event at '{schedule.EventBuilding}', but there was no event there");
                }
                else if (StartMovingToVisitBuilding(instance, citizenId, ref citizen, schedule.EventBuilding))
                {
                    returnTime = cityEvent.EndTime;
                    Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanna attend an event at '{schedule.EventBuilding}', will return at {returnTime}");
                }

                schedule.Schedule(ResidentState.Unknown, returnTime);
                schedule.EventBuilding = 0;
                return;
            }

            uint          relaxChance = spareTimeBehavior.GetGoOutChance(CitizenProxy.GetAge(ref citizen));
            ResidentState nextState   = Random.ShouldOccur(relaxChance)
                    ? ResidentState.Unknown
                    : ResidentState.Relaxing;

            schedule.Schedule(nextState, default);

            if (schedule.CurrentState != ResidentState.Relaxing)
            {
                Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} in state {schedule.CurrentState} wanna relax and then schedules {nextState}, heading to an entertainment building.");
                residentAI.FindVisitPlace(instance, citizenId, buildingId, residentAI.GetEntertainmentReason(instance));
            }
        }
示例#13
0
        /// <summary>
        /// Gets the <see cref="ICityEvent"/> instance of an upcoming city event whose start time is between the specified values.
        /// </summary>
        /// <param name="earliestStartTime">The earliest city event start time to consider.</param>
        /// <param name="latestStartTime">The latest city event start time to consider.</param>
        /// <returns>An <see cref="ICityEvent"/> instance of the first matching city event, or null if none found.</returns>
        public ICityEvent GetUpcomingCityEvent(DateTime earliestStartTime, DateTime latestStartTime)
        {
            if (upcomingEvents.Count == 0)
            {
                return(null);
            }

            ICityEvent upcomingEvent = upcomingEvents.First.Value;

            return(upcomingEvent.StartTime >= earliestStartTime && upcomingEvent.StartTime <= latestStartTime
                ? upcomingEvent
                : null);
        }
示例#14
0
        public void Process(ICityEvent cityEvent)
        {
            List <Trigger> list;

            if (!triggers.TryGetValue(cityEvent.GetType(), out list))
            {
                return;
            }

            foreach (var trigger in list.Where(t => t.DynamicCondition.IsFulfilled(cityEvent)))
            {
                trigger.Action.Execute(cityEvent.GameObject);
            }
        }
示例#15
0
        private void DisplayCityEvent(ICityEvent cityEvent, DateTime todayStart, DateTime todayEnd)
        {
            float startPercent = cityEvent.StartTime <= todayStart
                ? 0
                : (float)cityEvent.StartTime.TimeOfDay.TotalHours / 24f;

            float endPercent = cityEvent.EndTime >= todayEnd
                ? 1f
                : (float)cityEvent.EndTime.TimeOfDay.TotalHours / 24f;

            float startPosition = progressSprite.width * startPercent;
            float endPosition   = progressSprite.width * endPercent;

            UISprite eventSprite = progressSprite.AddUIComponent <UISprite>();

            eventSprite.name             = UISpriteEvent + cityEvent.BuildingId;
            eventSprite.relativePosition = new Vector3(startPosition, 0);
            eventSprite.atlas            = progressSprite.atlas;
            eventSprite.spriteName       = progressSprite.spriteName;
            eventSprite.height           = progressSprite.height;
            eventSprite.width            = endPosition - startPosition;
            eventSprite.fillDirection    = UIFillDirection.Horizontal;
            eventSprite.color            = GetColor(cityEvent.Color, EventSpriteOpacity);
            eventSprite.fillAmount       = 1f;
            eventSprite.SendToBack();
            eventSprite.objectUserData = cityEvent;
            eventSprite.eventClicked  += EventSprite_Clicked;
            SetEventTooltip(eventSprite, todayStart, todayEnd);

            var spriteBounds      = eventSprite.GetBounds();
            var overlappingEvents = displayedEventSprites
                                    .Where(e => e.GetBounds().Intersects(spriteBounds))
                                    .ToList();

            if (overlappingEvents.Count > 0)
            {
                overlappingEvents.Add(eventSprite);
                var itemCount       = overlappingEvents.Count;
                var newSpriteHeight = progressSprite.height / itemCount;
                for (int i = 0; i < itemCount; ++i)
                {
                    var sprite = overlappingEvents[i];
                    sprite.height           = newSpriteHeight;
                    sprite.relativePosition = new Vector3(sprite.relativePosition.x, i * newSpriteHeight);
                }
            }

            displayedEventSprites.Add(eventSprite);
        }
示例#16
0
        private bool RemoveCanceledEvents()
        {
            if (lastActiveEvent != null && MustCancelEvent(lastActiveEvent))
            {
                lastActiveEvent = null;
            }

            bool eventsChanged = false;

            if (activeEvent != null && MustCancelEvent(activeEvent))
            {
                Log.Debug(LogCategory.Events, $"The active event in building {activeEvent.BuildingId} must be canceled");
                activeEvent   = null;
                eventsChanged = true;
            }

            if (upcomingEvents.Count == 0)
            {
                return(eventsChanged);
            }

            LinkedListNode <ICityEvent> cityEvent = upcomingEvents.First;

            while (cityEvent != null)
            {
                if (MustCancelEvent(cityEvent.Value))
                {
                    Log.Debug(LogCategory.Events, $"The upcoming event in building {cityEvent.Value.BuildingId} must be canceled");
                    eventsChanged = true;
                    LinkedListNode <ICityEvent> nextEvent = cityEvent.Next;
                    upcomingEvents.Remove(cityEvent);
                    cityEvent = nextEvent;
                }
                else
                {
                    cityEvent = cityEvent.Next;
                }
            }

            return(eventsChanged);
        }
示例#17
0
        /// <summary>
        /// Searches for an upcoming event and checks whether the specified citizen ca attend it.
        /// Returns null if no matching events found.
        /// </summary>
        ///
        /// <param name="citizenId">The ID of the citizen to check.</param>
        /// <param name="citizen">The citizen data reference.</param>
        ///
        /// <returns>The city event or null if none found.</returns>
        protected ICityEvent GetUpcomingEventToAttend(uint citizenId, ref TCitizen citizen)
        {
            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            if (EventMgr.GetEventState(currentBuilding, DateTime.MaxValue) == CityEventState.Ongoing)
            {
                return(null);
            }

            DateTime earliestStart = TimeInfo.Now.AddHours(MinTravelTime);
            DateTime latestStart   = TimeInfo.Now.AddHours(MaxTravelTime);

            ICityEvent upcomingEvent = EventMgr.GetUpcomingCityEvent(earliestStart, latestStart);

            if (upcomingEvent != null && CanAttendEvent(citizenId, ref citizen, upcomingEvent))
            {
                return(upcomingEvent);
            }

            return(null);
        }
示例#18
0
        private bool MustCancelEvent(ICityEvent cityEvent)
        {
            if (!config.AreEventsEnabled && cityEvent is RealTimeCityEvent)
            {
                return(true);
            }

            const Building.Flags flags = Building.Flags.Abandoned | Building.Flags.BurnedDown | Building.Flags.Collapsed
                                         | Building.Flags.Deleted | Building.Flags.Demolishing | Building.Flags.Evacuating | Building.Flags.Flooded;

            if (buildingManager.BuildingHasFlags(cityEvent.BuildingId, flags, includeZero: true))
            {
                return(true);
            }

            if (cityEvent is VanillaEvent vanillaEvent)
            {
                EventData.Flags eventFlags = eventManager.GetEventFlags(vanillaEvent.EventId);
                return(eventFlags == 0 || (eventFlags & (EventData.Flags.Cancelled | EventData.Flags.Deleted)) != 0);
            }

            return(false);
        }
示例#19
0
        /// <summary>
        /// Lets the provided citizen try attending the next upcoming event.
        /// </summary>
        ///
        /// <param name="citizenId">The citizen ID.</param>
        /// <param name="citizen">The citizen data reference.</param>
        /// <param name="eventBuildingId">The building ID where the upcoming event will take place.</param>
        ///
        /// <returns><c>true</c> if the provided citizen will attend the next event; otherwise, <c>false</c>.</returns>
        protected bool AttendUpcomingEvent(uint citizenId, ref TCitizen citizen, out ushort eventBuildingId)
        {
            eventBuildingId = default;

            ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen);

            if (EventMgr.GetEventState(currentBuilding, DateTime.MaxValue) == CityEventState.Ongoing)
            {
                return(false);
            }

            DateTime earliestStart = TimeInfo.Now.AddHours(MinHoursOnTheWay);
            DateTime latestStart   = TimeInfo.Now.AddHours(MaxHoursOnTheWay);

            ICityEvent upcomingEvent = EventMgr.GetUpcomingCityEvent(earliestStart, latestStart);

            if (upcomingEvent != null && CanAttendEvent(citizenId, ref citizen, upcomingEvent))
            {
                eventBuildingId = upcomingEvent.BuildingId;
                return(true);
            }

            return(false);
        }
示例#20
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);
        }
示例#21
0
        private bool DoScheduledRelaxing(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen)
        {
            // Relaxing was already scheduled last time, but the citizen is still at school/work or in shelter.
            // This can occur when the game's transfer manager can't find any activity for the citizen.
            // In that case, move back home.
            if ((schedule.CurrentState == ResidentState.AtSchoolOrWork || schedule.CurrentState == ResidentState.InShelter) &&
                schedule.LastScheduledState == ResidentState.Relaxing)
            {
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted relax but is still at work or in shelter. No relaxing activity found. Now going home.");
                return(false);
            }

            ushort buildingId = CitizenProxy.GetCurrentBuilding(ref citizen);

            switch (schedule.Hint)
            {
            case ScheduleHint.RelaxAtLeisureBuilding:
                schedule.Schedule(ResidentState.Unknown);

                ushort leisure = MoveToLeisureBuilding(instance, citizenId, ref citizen, buildingId);
                if (leisure == 0)
                {
                    Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted relax but didn't find a leisure building");
                    return(false);
                }

                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} heading to a leisure building {leisure}");
                return(true);

            case ScheduleHint.AttendingEvent:
                ushort eventBuilding = schedule.EventBuilding;
                schedule.EventBuilding = 0;

                ICityEvent cityEvent = EventMgr.GetCityEvent(eventBuilding);
                if (cityEvent == null)
                {
                    Log.Debug(LogCategory.Events, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted attend an event at '{eventBuilding}', but there was no event there");
                }
                else if (StartMovingToVisitBuilding(instance, citizenId, ref citizen, eventBuilding))
                {
                    schedule.Schedule(ResidentState.Unknown, cityEvent.EndTime);
                    Log.Debug(LogCategory.Events, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanna attend an event at '{eventBuilding}', will return at {cityEvent.EndTime}");
                    return(true);
                }

                schedule.Schedule(ResidentState.Unknown);
                return(false);

            case ScheduleHint.RelaxNearbyOnly:
                Vector3 currentPosition = CitizenMgr.GetCitizenPosition(CitizenProxy.GetInstance(ref citizen));
                ushort  parkBuildingId  = BuildingMgr.FindActiveBuilding(currentPosition, LocalSearchDistance, ItemClass.Service.Beautification);
                if (StartMovingToVisitBuilding(instance, citizenId, ref citizen, parkBuildingId))
                {
                    Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} heading to a nearby entertainment building {parkBuildingId}");
                    schedule.Schedule(ResidentState.Unknown);
                    return(true);
                }

                schedule.Schedule(ResidentState.Unknown);
                DoScheduledHome(ref schedule, instance, citizenId, ref citizen);
                return(true);
            }

            uint relaxChance = spareTimeBehavior.GetRelaxingChance(
                CitizenProxy.GetAge(ref citizen),
                schedule.WorkShift,
                schedule.WorkStatus == WorkStatus.OnVacation);

            relaxChance = AdjustRelaxChance(relaxChance, ref citizen);

            ResidentState nextState = Random.ShouldOccur(relaxChance)
                    ? ResidentState.Relaxing
                    : ResidentState.Unknown;

            schedule.Schedule(nextState);
            if (schedule.CurrentState != ResidentState.Relaxing || Random.ShouldOccur(FindAnotherShopOrEntertainmentChance))
            {
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} in state {schedule.CurrentState} wanna relax and then schedules {nextState}, heading to an entertainment building.");
                residentAI.FindVisitPlace(instance, citizenId, buildingId, residentAI.GetEntertainmentReason(instance));
            }
#if DEBUG
            else
            {
                Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} continues relaxing in the same entertainment building.");
            }
#endif

            return(true);
        }
示例#22
0
 public bool IsFulfilled(ICityEvent cityEvent)
 {
     return(cityEvent.Parameters.type == type);
 }
示例#23
0
        private bool SynchronizeWithVanillaEvents()
        {
            bool result = false;

            DateTime today = timeInfo.Now.Date;

            foreach (ushort eventId in eventManager.GetUpcomingEvents(today, today.AddDays(1)))
            {
                if (!eventManager.TryGetEventInfo(eventId, out ushort buildingId, out DateTime startTime, out float duration, out float ticketPrice))
                {
                    continue;
                }

                if (startTime.AddHours(duration) < timeInfo.Now)
                {
                    continue;
                }

                VanillaEvent existingVanillaEvent = CityEvents
                                                    .OfType <VanillaEvent>()
                                                    .FirstOrDefault(e => e.BuildingId == buildingId && e.EventId == eventId);

                if (existingVanillaEvent != null)
                {
                    if (Math.Abs((startTime - existingVanillaEvent.StartTime).TotalMinutes) <= 5d)
                    {
                        continue;
                    }
                    else if (existingVanillaEvent == activeEvent)
                    {
                        activeEvent = null;
                    }
                    else
                    {
                        upcomingEvents.Remove(existingVanillaEvent);
                    }
                }

                DateTime adjustedStartTime = AdjustEventStartTime(startTime, randomize: false);
                if (adjustedStartTime != startTime)
                {
                    startTime = adjustedStartTime;
                    eventManager.SetStartTime(eventId, startTime);
                }

                var newEvent = new VanillaEvent(eventId, duration, ticketPrice);
                newEvent.Configure(buildingId, buildingManager.GetBuildingName(buildingId), startTime);
                result = true;
                Log.Debug(LogCategory.Events, timeInfo.Now, $"Vanilla event registered for {newEvent.BuildingId}, start time {newEvent.StartTime}, end time {newEvent.EndTime}");

                LinkedListNode <ICityEvent> existingEvent = upcomingEvents.FirstOrDefaultNode(e => e.StartTime >= startTime);
                if (existingEvent == null)
                {
                    upcomingEvents.AddLast(newEvent);
                }
                else
                {
                    upcomingEvents.AddBefore(existingEvent, newEvent);
                    if (existingEvent.Value.StartTime < newEvent.EndTime && existingEvent.Value is RealTimeCityEvent)
                    {
                        // Avoid multiple events at the same time - vanilla events have priority
                        upcomingEvents.Remove(existingEvent);
                        earliestEvent = newEvent.EndTime.AddHours(12f);
                    }
                }
            }

            return(result);
        }