private bool RescheduleAtHome(ref CitizenSchedule schedule, uint citizenId, ref TCitizen citizen) { if (schedule.CurrentState != ResidentState.AtHome || TimeInfo.Now < schedule.ScheduledStateTime) { return(false); } if (schedule.ScheduledState != ResidentState.Relaxing && schedule.ScheduledState != ResidentState.Shopping) { return(false); } if (schedule.ScheduledState != ResidentState.Shopping && WeatherInfo.IsBadWeather) { Log.Debug(LogCategory.Schedule, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} re-schedules an activity because of bad weather"); schedule.Schedule(ResidentState.Unknown); return(true); } Citizen.AgeGroup age = CitizenProxy.GetAge(ref citizen); uint goingOutChance = schedule.ScheduledState == ResidentState.Shopping ? spareTimeBehavior.GetShoppingChance(age) : spareTimeBehavior.GetRelaxingChance(age, schedule.WorkShift); if (goingOutChance > 0) { return(false); } Log.Debug(LogCategory.Schedule, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} re-schedules an activity because of time"); schedule.Schedule(ResidentState.Unknown); return(true); }
private bool RescheduleAtHome(ref CitizenSchedule schedule, ref TCitizen citizen) { if (schedule.CurrentState != ResidentState.AtHome || TimeInfo.Now < schedule.ScheduledStateTime) { return(false); } if (schedule.ScheduledState != ResidentState.Relaxing && schedule.ScheduledState != ResidentState.Shopping) { return(false); } if (IsBadWeather()) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(0, ref citizen)} re-schedules an activity because of bad weather (see next line for citizen ID)"); schedule.Schedule(ResidentState.Unknown, default); return(true); } uint goOutChance = spareTimeBehavior.GetGoOutChance( CitizenProxy.GetAge(ref citizen), schedule.WorkShift, schedule.ScheduledState == ResidentState.Shopping); if (Random.ShouldOccur(goOutChance)) { return(false); } Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(0, ref citizen)} re-schedules an activity because of time (see next line for citizen ID)"); schedule.Schedule(ResidentState.Unknown, default); return(true); }
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 bool RescheduleVisit(ref CitizenSchedule schedule, ref TCitizen citizen, ushort currentBuilding) { if (schedule.ScheduledState != ResidentState.Relaxing && schedule.ScheduledState != ResidentState.Shopping && schedule.ScheduledState != ResidentState.Visiting) { return(false); } if (IsBadWeather()) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(0, ref citizen)} quits a visit because of bad weather (see next line for citizen ID)"); schedule.Schedule(ResidentState.AtHome, default); return(true); } if (IsBuildingNoiseRestricted(currentBuilding, currentBuilding)) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(0, ref citizen)} quits a visit because of NIMBY policy (see next line for citizen ID)"); schedule.Schedule(ResidentState.Unknown, default); return(true); } uint stayChance = spareTimeBehavior.GetGoOutChance(CitizenProxy.GetAge(ref citizen)); if (!Random.ShouldOccur(stayChance)) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(0, ref citizen)} quits a visit because of time (see next line for citizen ID)"); schedule.Schedule(ResidentState.AtHome, default); return(true); } return(false); }
private void DoScheduledShopping(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen) { ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); if (schedule.Hint == ScheduleHint.LocalShoppingOnly) { schedule.Schedule(ResidentState.Unknown, default); ushort shop = MoveToCommercialBuilding(instance, citizenId, ref citizen, LocalSearchDistance); if (shop == 0) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted go shopping, but didn't find a local shop"); } else { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} goes shopping at a local shop {shop}"); } } else { uint moreShoppingChance = spareTimeBehavior.GetGoOutChance(CitizenProxy.GetAge(ref citizen)); ResidentState nextState = Random.ShouldOccur(moreShoppingChance) ? ResidentState.Unknown : ResidentState.Shopping; schedule.Schedule(nextState, default); if (schedule.CurrentState != ResidentState.Shopping) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} in state {schedule.CurrentState} wanna go shopping and schedules {nextState}, heading to a random shop"); residentAI.FindVisitPlace(instance, citizenId, currentBuilding, residentAI.GetShoppingReason(instance)); } } }
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 bool DoScheduledShopping(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen) { // Shopping 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.Shopping) { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted go shopping but is still at work or in shelter. No shopping activity found. Now going home."); return(false); } ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); if (schedule.Hint == ScheduleHint.LocalShoppingOnly) { schedule.Schedule(ResidentState.Unknown); ushort shop = MoveToCommercialBuilding(instance, citizenId, ref citizen, LocalSearchDistance); if (shop == 0) { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted go shopping, but didn't find a local shop"); return(false); } if (TimeInfo.IsNightTime) { schedule.Hint = ScheduleHint.NoShoppingAnyMore; } Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} goes shopping at a local shop {shop}"); return(true); } uint moreShoppingChance = spareTimeBehavior.GetShoppingChance(CitizenProxy.GetAge(ref citizen)); ResidentState nextState = schedule.Hint != ScheduleHint.NoShoppingAnyMore && Random.ShouldOccur(moreShoppingChance) ? ResidentState.Shopping : ResidentState.Unknown; schedule.Schedule(nextState); if (schedule.CurrentState != ResidentState.Shopping || Random.ShouldOccur(FindAnotherShopOrEntertainmentChance)) { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} in state {schedule.CurrentState} wanna go shopping and schedules {nextState}, heading to a random shop, hint = {schedule.Hint}"); residentAI.FindVisitPlace(instance, citizenId, currentBuilding, residentAI.GetShoppingReason(instance)); } #if DEBUG else { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} continues shopping in the same building."); } #endif return(true); }
private bool ProcessCitizenMoving(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen) { ushort instanceId = CitizenProxy.GetInstance(ref citizen); ushort vehicleId = CitizenProxy.GetVehicle(ref citizen); if (vehicleId == 0 && instanceId == 0) { if (CitizenProxy.GetVisitBuilding(ref citizen) != 0) { CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0); } if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.MovingIn)) { CitizenMgr.ReleaseCitizen(citizenId); schedule = default; } else { CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home); CitizenProxy.SetArrested(ref citizen, false); schedule.Schedule(ResidentState.Unknown); } return(true); } if (vehicleId == 0 && CitizenMgr.IsAreaEvacuating(instanceId) && !CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating)) { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} was on the way, but the area evacuates. Finding an evacuation place."); schedule.Schedule(ResidentState.Unknown); TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, residentAI.GetEvacuationReason(instance, 0)); return(true); } ushort targetBuilding = CitizenMgr.GetTargetBuilding(instanceId); if (targetBuilding == CitizenProxy.GetWorkBuilding(ref citizen)) { return(true); } ItemClass.Service targetService = BuildingMgr.GetBuildingService(targetBuilding); if (targetService == ItemClass.Service.Beautification && WeatherInfo.IsBadWeather) { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} cancels the trip to a park due to bad weather"); schedule.Schedule(ResidentState.AtHome); return(false); } return(true); }
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>Updates the citizen's work schedule by determining the time for going to work.</summary> /// <param name="schedule">The citizen's schedule to update.</param> /// <param name="currentBuilding">The ID of the building where the citizen is currently located.</param> /// <param name="simulationCycle">The duration (in hours) of a full citizens simulation cycle.</param> /// <returns><c>true</c> if work was scheduled; otherwise, <c>false</c>.</returns> public bool ScheduleGoToWork(ref CitizenSchedule schedule, ushort currentBuilding, float simulationCycle) { if (schedule.CurrentState == ResidentState.AtSchoolOrWork) { return(false); } DateTime now = timeInfo.Now; if (config.IsWeekendEnabled && now.IsWeekend() && !schedule.WorksOnWeekends) { return(false); } float travelTime = GetTravelTimeToWork(ref schedule, currentBuilding); DateTime workEndTime = now.FutureHour(schedule.WorkShiftEndHour); DateTime departureTime = now.FutureHour(schedule.WorkShiftStartHour - travelTime - simulationCycle); if (departureTime > workEndTime && now.AddHours(travelTime + simulationCycle) < workEndTime) { departureTime = now; } schedule.Schedule(ResidentState.AtSchoolOrWork, departureTime); return(true); }
/// <summary>Updates the citizen's work schedule by determining the returning from lunch time.</summary> /// <param name="schedule">The citizen's schedule to update.</param> public void ScheduleReturnFromLunch(ref CitizenSchedule schedule) { if (schedule.WorkStatus == WorkStatus.Working) { schedule.Schedule(ResidentState.AtSchoolOrWork, lunchEnd); } }
private bool ScheduleShopping(ref CitizenSchedule schedule, ref TCitizen citizen, bool localOnly) { // If the citizen doesn't need any goods, he/she still can go shopping just for fun if (!CitizenProxy.HasFlags(ref citizen, Citizen.Flags.NeedGoods)) { if (schedule.Hint == ScheduleHint.NoShoppingAnyMore || WeatherInfo.IsBadWeather || !Random.ShouldOccur(Config.ShoppingForFunQuota)) { schedule.Hint = ScheduleHint.None; return(false); } schedule.Hint = ScheduleHint.NoShoppingAnyMore; } else { schedule.Hint = ScheduleHint.None; } if (!Random.ShouldOccur(spareTimeBehavior.GetShoppingChance(CitizenProxy.GetAge(ref citizen)))) { return(false); } if (TimeInfo.IsNightTime || localOnly || Random.ShouldOccur(Config.LocalBuildingSearchQuota)) { schedule.Hint = ScheduleHint.LocalShoppingOnly; } schedule.Schedule(ResidentState.Shopping); return(true); }
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 ScheduleShopping(ref CitizenSchedule schedule, ref TCitizen citizen, bool localOnly) { if (!CitizenProxy.HasFlags(ref citizen, Citizen.Flags.NeedGoods) || IsBadWeather()) { return(false); } if (!Random.ShouldOccur(spareTimeBehavior.GetGoOutChance(CitizenProxy.GetAge(ref citizen))) || !Random.ShouldOccur(GoShoppingChance)) { return(false); } if (TimeInfo.IsNightTime || localOnly || Random.ShouldOccur(Config.LocalBuildingSearchQuota)) { schedule.Hint = ScheduleHint.LocalShoppingOnly; } else { schedule.Hint = ScheduleHint.None; } schedule.Schedule(ResidentState.Shopping, default); return(true); }
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"); } }
private void DoScheduledEvacuation(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen) { ushort building = CitizenProxy.GetCurrentBuilding(ref citizen); if (building == 0) { schedule.Schedule(ResidentState.AtHome); return; } schedule.Schedule(ResidentState.InShelter); if (schedule.CurrentState != ResidentState.InShelter) { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is trying to find an evacuation place"); residentAI.FindEvacuationPlace(instance, citizenId, building, residentAI.GetEvacuationReason(instance, building)); } }
private bool ProcessCitizenVisit(ref CitizenSchedule schedule, ref TCitizen citizen) { if (schedule.Hint == ScheduleHint.OnTour) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(0, ref citizen)} quits a tour (see next line for citizen ID)"); schedule.Schedule(ResidentState.Unknown, default); return(true); } return(RescheduleVisit(ref schedule, ref citizen, CitizenProxy.GetVisitBuilding(ref citizen))); }
/// <summary>Updates the citizen's work schedule by determining the time for returning from work.</summary> /// <param name="schedule">The citizen's schedule to update.</param> /// <param name="citizenAge">The age of the citizen.</param> public void ScheduleReturnFromWork(ref CitizenSchedule schedule, Citizen.AgeGroup citizenAge) { if (schedule.WorkStatus != WorkStatus.Working) { return; } float departureHour = schedule.WorkShiftEndHour + GetOvertime(citizenAge); schedule.Schedule(ResidentState.Unknown, timeInfo.Now.FutureHour(departureHour)); }
private bool ProcessCitizenVisit(ref CitizenSchedule schedule, uint citizenId, ref TCitizen citizen) { if (schedule.Hint == ScheduleHint.OnTour) { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} quits a tour"); schedule.Schedule(ResidentState.Unknown); return(true); } return(RescheduleVisit(ref schedule, citizenId, ref citizen, CitizenProxy.GetVisitBuilding(ref citizen))); }
private bool RescheduleVisit(ref CitizenSchedule schedule, uint citizenId, ref TCitizen citizen, ushort currentBuilding) { switch (schedule.ScheduledState) { case ResidentState.Shopping: case ResidentState.Relaxing: case ResidentState.Visiting: break; default: return(false); } if (schedule.CurrentState != ResidentState.Shopping && WeatherInfo.IsBadWeather) { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} quits a visit because of bad weather"); schedule.Schedule(ResidentState.AtHome); return(true); } if (buildingAI.IsNoiseRestricted(currentBuilding, currentBuilding)) { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} quits a visit because of NIMBY policy"); schedule.Schedule(ResidentState.Unknown); return(true); } Citizen.AgeGroup age = CitizenProxy.GetAge(ref citizen); uint stayChance = schedule.CurrentState == ResidentState.Shopping ? spareTimeBehavior.GetShoppingChance(age) : spareTimeBehavior.GetRelaxingChance(age, schedule.WorkShift, schedule.WorkStatus == WorkStatus.OnVacation); if (!Random.ShouldOccur(stayChance)) { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} quits a visit because of time"); schedule.Schedule(ResidentState.AtHome); return(true); } return(false); }
private bool ProcessCitizenInShelter(ref CitizenSchedule schedule, ref TCitizen citizen) { ushort shelter = CitizenProxy.GetVisitBuilding(ref citizen); if (BuildingMgr.BuildingHasFlags(shelter, Building.Flags.Downgrading)) { schedule.Schedule(ResidentState.Unknown, default); return(true); } return(false); }
private bool ProcessCitizenInShelter(ref CitizenSchedule schedule, ref TCitizen citizen) { ushort shelter = CitizenProxy.GetVisitBuilding(ref citizen); if (BuildingMgr.BuildingHasFlags(shelter, Building.Flags.Downgrading) && schedule.ScheduledState == ResidentState.InShelter) { CitizenProxy.RemoveFlags(ref citizen, Citizen.Flags.Evacuating); schedule.Schedule(ResidentState.Unknown); return(true); } return(false); }
/// <summary>Updates the citizen's work schedule by determining the lunch time.</summary> /// <param name="schedule">The citizen's schedule to update.</param> /// <param name="citizenAge">The citizen's age.</param> /// <returns><c>true</c> if a lunch time was scheduled; otherwise, <c>false</c>.</returns> public bool ScheduleLunch(ref CitizenSchedule schedule, Citizen.AgeGroup citizenAge) { if (timeInfo.Now < lunchBegin && schedule.WorkStatus == WorkStatus.Working && schedule.WorkShift == WorkShift.First && WillGoToLunch(citizenAge)) { schedule.Schedule(ResidentState.Shopping, lunchBegin); return(true); } return(false); }
private void ExecuteCitizenSchedule(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen, bool noReschedule) { if (ProcessCurrentState(ref schedule, citizenId, ref citizen) && schedule.ScheduledState == ResidentState.Unknown && !noReschedule) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} will re-schedule now"); // If the state processing changed the schedule, we need to update it UpdateCitizenSchedule(ref schedule, citizenId, ref citizen); } if (TimeInfo.Now < schedule.ScheduledStateTime) { return; } if (schedule.CurrentState == ResidentState.AtHome && IsCitizenVirtual(instance, ref citizen, ShouldRealizeCitizen)) { Log.Debug($" *** Citizen {citizenId} is virtual this time"); schedule.Schedule(ResidentState.Unknown, default); return; } switch (schedule.ScheduledState) { case ResidentState.AtHome: DoScheduledHome(ref schedule, instance, citizenId, ref citizen); break; case ResidentState.AtSchoolOrWork: DoScheduledWork(ref schedule, instance, citizenId, ref citizen); break; case ResidentState.Shopping when schedule.WorkStatus == WorkStatus.Working: DoScheduledLunch(ref schedule, instance, citizenId, ref citizen); break; case ResidentState.Shopping: DoScheduledShopping(ref schedule, instance, citizenId, ref citizen); break; case ResidentState.Relaxing: DoScheduledRelaxing(ref schedule, instance, citizenId, ref citizen); break; case ResidentState.InShelter: DoScheduledEvacuation(ref schedule, instance, citizenId, ref citizen); break; } }
private void DoScheduledEvacuation(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen) { schedule.Schedule(ResidentState.Unknown); ushort building = CitizenProxy.GetCurrentBuilding(ref citizen); if (building == 0) { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is trying to find a shelter from current position"); TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, residentAI.GetEvacuationReason(instance, 0)); } else { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is trying to find a shelter from {building}"); residentAI.FindEvacuationPlace(instance, citizenId, building, residentAI.GetEvacuationReason(instance, building)); } }
private void DoScheduledWork(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen) { ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); schedule.WorkStatus = WorkStatus.Working; if (currentBuilding == schedule.WorkBuilding && schedule.CurrentState != ResidentState.AtSchoolOrWork) { CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0); CitizenProxy.SetLocation(ref citizen, Citizen.Location.Work); return; } #if DEBUG string citizenDesc = GetCitizenDesc(citizenId, ref citizen); #else const string citizenDesc = null; #endif if (residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, schedule.WorkBuilding)) { if (schedule.CurrentState != ResidentState.AtHome) { // The start moving method will register a departure from any building to work, // but we are only interested in the 'home->work' route. schedule.DepartureTime = default; } Citizen.AgeGroup citizenAge = CitizenProxy.GetAge(ref citizen); if (workBehavior.ScheduleLunch(ref schedule, citizenAge)) { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{citizenDesc} is going from {currentBuilding} to school/work {schedule.WorkBuilding} and will go to lunch at {schedule.ScheduledStateTime}"); } else { workBehavior.ScheduleReturnFromWork(ref schedule, citizenAge); Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{citizenDesc} is going from {currentBuilding} to school/work {schedule.WorkBuilding} and will leave work at {schedule.ScheduledStateTime}"); } } else { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted to go to work from {currentBuilding} but can't, will try once again next time"); schedule.Schedule(ResidentState.Unknown); } }
private bool ScheduleWork(ref CitizenSchedule schedule, ref TCitizen citizen) { ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); if (!workBehavior.ScheduleGoToWork(ref schedule, currentBuilding, simulationCycle)) { return(false); } Log.Debug($" - Schedule work at {schedule.ScheduledStateTime}"); float timeLeft = (float)(schedule.ScheduledStateTime - TimeInfo.Now).TotalHours; if (timeLeft <= PrepareToWorkHours) { // Just sit at home if the work time will come soon Log.Debug($" - Work time in {timeLeft} hours, preparing for departure"); return(true); } if (timeLeft <= MaxTravelTime) { if (schedule.CurrentState != ResidentState.AtHome) { Log.Debug($" - Work time in {timeLeft} hours, returning home"); schedule.Schedule(ResidentState.AtHome, default); return(true); } // If we have some time, try to shop locally. if (ScheduleShopping(ref schedule, ref citizen, true)) { Log.Debug($" - Work time in {timeLeft} hours, trying local shop"); } else { Log.Debug($" - Work time in {timeLeft} hours, doing nothing"); } return(true); } return(false); }
private void DoScheduledWork(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen) { ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); schedule.WorkStatus = WorkStatus.Working; schedule.DepartureToWorkTime = default; if (currentBuilding == schedule.WorkBuilding && schedule.CurrentState != ResidentState.AtSchoolOrWork) { CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0); CitizenProxy.SetLocation(ref citizen, Citizen.Location.Work); return; } if (residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, schedule.WorkBuilding)) { if (schedule.CurrentState == ResidentState.AtHome) { schedule.DepartureToWorkTime = TimeInfo.Now; } Citizen.AgeGroup citizenAge = CitizenProxy.GetAge(ref citizen); if (workBehavior.ScheduleLunch(ref schedule, citizenAge)) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is going from {currentBuilding} to school/work {schedule.WorkBuilding} and will go to lunch at {schedule.ScheduledStateTime}"); } else { workBehavior.ScheduleReturnFromWork(ref schedule, citizenAge); Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is going from {currentBuilding} to school/work {schedule.WorkBuilding} and will leave work at {schedule.ScheduledStateTime}"); } } else { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanted to go to work from {currentBuilding} but can't, will try once again next time"); schedule.Schedule(ResidentState.Unknown, default); } }
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); }
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); }