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); }
/// <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); }
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(); } }
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}"); }
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); }
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}"); }
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)); }
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); }
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(); } }
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)); } }
/// <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); }
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); } }
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); }
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); }
/// <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); }
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); }
/// <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); }
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); }
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); }
public bool IsFulfilled(ICityEvent cityEvent) { return(cityEvent.Parameters.type == type); }
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); }