private bool CitizenGoesRelaxing(TAI instance, uint citizenId, ref TCitizen citizen) { Citizen.AgeGroup citizenAge = CitizenProxy.GetAge(ref citizen); if (!IsChance(GetGoOutChance(citizenAge))) { return(false); } ushort buildingId = CitizenProxy.GetCurrentBuilding(ref citizen); if (buildingId == 0) { return(false); } if (TimeInfo.IsNightTime) { ushort leisure = MoveToLeisure(instance, citizenId, ref citizen, buildingId); Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanna relax at night, trying leisure area '{leisure}'"); return(leisure != 0); } if (CitizenProxy.GetWorkBuilding(ref citizen) != 0 && IsWorkDayMorning(citizenAge)) { return(false); } Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanna relax, heading to an entertainment place"); residentAI.FindVisitPlace(instance, citizenId, buildingId, residentAI.GetEntertainmentReason(instance)); return(true); }
/// <summary> /// Gets a string that describes the specified citizen. /// </summary> /// /// <param name="citizenId">The citizen ID.</param> /// <param name="citizen">The citizen data reference.</param> /// /// <returns>A short string describing the specified citizen.</returns> protected string GetCitizenDesc(uint citizenId, ref TCitizen citizen) { ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen); string home = homeBuilding == 0 ? "homeless" : "lives at " + homeBuilding; ushort workBuilding = CitizenProxy.GetWorkBuilding(ref citizen); string employment = workBuilding == 0 ? "unemployed" : "works at " + workBuilding; Citizen.Location location = CitizenProxy.GetLocation(ref citizen); return($"Citizen {citizenId} ({CitizenProxy.GetAge(ref citizen)}, {home}, {employment}, currently {location} at {CitizenProxy.GetCurrentBuilding(ref citizen)}) / instance {CitizenProxy.GetInstance(ref citizen)}"); }
/// <summary> /// Gets a string that describes the provided citizen. /// </summary> /// /// <param name="citizenId">The citizen ID.</param> /// <param name="citizen">The citizen data reference.</param> /// <param name="isVirtual"><c>true</c> if the citizen is in a virtual mode; otherwise, <c>false</c>.</param> /// /// <returns>A short string describing the provided citizen.</returns> protected string GetCitizenDesc(uint citizenId, ref TCitizen citizen, bool?isVirtual) { ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen); string home = homeBuilding == 0 ? "homeless" : "lives at " + homeBuilding; ushort workBuilding = CitizenProxy.GetWorkBuilding(ref citizen); string employment = workBuilding == 0 ? "unemployed" : "works at " + workBuilding; Citizen.Location location = CitizenProxy.GetLocation(ref citizen); string virt = isVirtual.HasValue ? (isVirtual.Value ? " (virtual)" : " (real)") : null; return($"Citizen {citizenId} ({CitizenProxy.GetAge(ref citizen)}, {home}, {employment}, currently {location} at {CitizenProxy.GetCurrentBuilding(ref citizen)}) / instance {CitizenProxy.GetInstance(ref citizen)}{virt}"); }
private 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 ProcessCitizenAtSchoolOrWork(TAI instance, uint citizenId, ref TCitizen citizen, bool isVirtual) { ushort workBuilding = CitizenProxy.GetWorkBuilding(ref citizen); if (workBuilding == 0) { Log.Debug($"WARNING: {GetCitizenDesc(citizenId, ref citizen, isVirtual)} is in corrupt state: at school/work with no work building. Teleporting home."); CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home); return; } ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); if (ShouldGoToLunch(CitizenProxy.GetAge(ref citizen), citizenId)) { ushort lunchPlace = MoveToCommercialBuilding(instance, citizenId, ref citizen, LocalSearchDistance, isVirtual); if (lunchPlace != 0) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} is going for lunch from {currentBuilding} to {lunchPlace}"); } else { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} wanted to go for lunch from {currentBuilding}, but there were no buildings close enough"); } return; } if (!ShouldReturnFromSchoolOrWork(citizenId, currentBuilding, CitizenProxy.GetAge(ref citizen))) { return; } Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} leaves their workplace {workBuilding}"); if (CitizenGoesToEvent(instance, citizenId, ref citizen, isVirtual)) { return; } if (!CitizenGoesShopping(instance, citizenId, ref citizen, isVirtual) && !CitizenGoesRelaxing(instance, citizenId, ref citizen, isVirtual)) { if (isVirtual) { CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home); } else { residentAI.StartMoving(instance, citizenId, ref citizen, workBuilding, CitizenProxy.GetHomeBuilding(ref citizen)); } } }
private bool CitizenGoesShopping(TAI instance, uint citizenId, ref TCitizen citizen, bool isVirtual) { if (!CitizenProxy.HasFlags(ref citizen, Citizen.Flags.NeedGoods) || IsBadWeather(citizenId)) { return(false); } if (TimeInfo.IsNightTime) { if (Random.ShouldOccur(GetGoOutChance(CitizenProxy.GetAge(ref citizen)))) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} wanna go shopping at night"); ushort localVisitPlace = MoveToCommercialBuilding(instance, citizenId, ref citizen, LocalSearchDistance, isVirtual); Log.DebugIf(localVisitPlace != 0, $"Citizen {citizenId} is going shopping at night to a local shop {localVisitPlace}"); return(localVisitPlace > 0); } return(false); } if (Random.ShouldOccur(GoShoppingChance)) { bool localOnly = CitizenProxy.GetWorkBuilding(ref citizen) != 0 && IsWorkDayMorning(CitizenProxy.GetAge(ref citizen)); ushort localVisitPlace = 0; if (Random.ShouldOccur(Config.LocalBuildingSearchQuota)) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} wanna go shopping"); localVisitPlace = MoveToCommercialBuilding(instance, citizenId, ref citizen, LocalSearchDistance, isVirtual); Log.DebugIf(localVisitPlace != 0, $"Citizen {citizenId} is going shopping to a local shop {localVisitPlace}"); } if (localVisitPlace == 0) { if (localOnly) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} wanna go shopping, but didn't find a local shop"); return(false); } Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} wanna go shopping, heading to a random shop"); residentAI.FindVisitPlace(instance, citizenId, CitizenProxy.GetHomeBuilding(ref citizen), residentAI.GetShoppingReason(instance)); } return(true); } return(false); }
private ushort MoveToLeisure(TAI instance, uint citizenId, ref TCitizen citizen, ushort buildingId) { ushort leisureBuilding = BuildingMgr.FindActiveBuilding( buildingId, LeisureSearchDistance, ItemClass.Service.Commercial, ItemClass.SubService.CommercialLeisure); if (leisureBuilding == CitizenProxy.GetWorkBuilding(ref citizen)) { return(0); } StartMovingToVisitBuilding(instance, citizenId, ref citizen, leisureBuilding); return(leisureBuilding); }
private bool CitizenGoesWorking(TAI instance, uint citizenId, ref TCitizen citizen) { ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen); ushort workBuilding = CitizenProxy.GetWorkBuilding(ref citizen); ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); if (!ShouldMoveToSchoolOrWork(workBuilding, currentBuilding, CitizenProxy.GetAge(ref citizen))) { return(false); } Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is going from {currentBuilding} ({CitizenProxy.GetLocation(ref citizen)}) to school/work {workBuilding}"); residentAI.StartMoving(instance, citizenId, ref citizen, homeBuilding, workBuilding); return(true); }
private bool CitizenGoesShopping(TAI instance, uint citizenId, ref TCitizen citizen) { if (!CitizenProxy.HasFlags(ref citizen, Citizen.Flags.NeedGoods)) { return(false); } if (TimeInfo.IsNightTime) { if (IsChance(GetGoOutChance(CitizenProxy.GetAge(ref citizen)))) { ushort localVisitPlace = MoveToCommercialBuilding(instance, citizenId, ref citizen, LocalSearchDistance); Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanna go shopping at night, trying local shop '{localVisitPlace}'"); return(localVisitPlace > 0); } return(false); } if (IsChance(GoShoppingChance)) { bool localOnly = CitizenProxy.GetWorkBuilding(ref citizen) != 0 && IsWorkDayMorning(CitizenProxy.GetAge(ref citizen)); ushort localVisitPlace = 0; if (IsChance(Config.LocalBuildingSearchQuota)) { localVisitPlace = MoveToCommercialBuilding(instance, citizenId, ref citizen, LocalSearchDistance); Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanna go shopping, tries a local shop '{localVisitPlace}'"); } if (localVisitPlace == 0) { if (localOnly) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanna go shopping, but didn't find a local shop"); return(false); } Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanna go shopping, heading to a random shop"); residentAI.FindVisitPlace(instance, citizenId, CitizenProxy.GetHomeBuilding(ref citizen), residentAI.GetShoppingReason(instance)); } return(true); } return(false); }
private void ProcessCitizenDead(TAI instance, uint citizenId, ref TCitizen citizen) { ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); Citizen.Location currentLocation = CitizenProxy.GetLocation(ref citizen); if (currentBuilding == 0 || (currentLocation == Citizen.Location.Moving && CitizenProxy.GetVehicle(ref citizen) == 0)) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is released"); residentSchedules[citizenId] = default; CitizenMgr.ReleaseCitizen(citizenId); return; } if (currentLocation != Citizen.Location.Home && CitizenProxy.GetHomeBuilding(ref citizen) != 0) { CitizenProxy.SetHome(ref citizen, citizenId, 0); } if (currentLocation != Citizen.Location.Work && CitizenProxy.GetWorkBuilding(ref citizen) != 0) { CitizenProxy.SetWorkplace(ref citizen, citizenId, 0); } if (currentLocation != Citizen.Location.Visit && CitizenProxy.GetVisitBuilding(ref citizen) != 0) { CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0); } if (currentLocation == Citizen.Location.Moving || CitizenProxy.GetVehicle(ref citizen) != 0) { return; } if (currentLocation == Citizen.Location.Visit && BuildingMgr.GetBuildingService(CitizenProxy.GetVisitBuilding(ref citizen)) == ItemClass.Service.HealthCare) { return; } residentAI.FindHospital(instance, citizenId, currentBuilding, TransferManager.TransferReason.Dead); Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is dead, body should get serviced"); }
private ushort MoveToCommercialBuilding(TAI instance, uint citizenId, ref TCitizen citizen, float distance) { ushort buildingId = CitizenProxy.GetCurrentBuilding(ref citizen); if (buildingId == 0) { return(0); } ushort foundBuilding = BuildingMgr.FindActiveBuilding(buildingId, distance, ItemClass.Service.Commercial); if (foundBuilding == CitizenProxy.GetWorkBuilding(ref citizen)) { return(0); } StartMovingToVisitBuilding(instance, citizenId, ref citizen, foundBuilding); return(foundBuilding); }
protected bool EnsureCitizenValid(uint citizenId, ref TCitizen citizen) { if (CitizenProxy.GetHomeBuilding(ref citizen) == 0 && CitizenProxy.GetWorkBuilding(ref citizen) == 0 && CitizenProxy.GetVisitBuilding(ref citizen) == 0 && CitizenProxy.GetInstance(ref citizen) == 0 && CitizenProxy.GetVehicle(ref citizen) == 0) { CitizenMgr.ReleaseCitizen(citizenId); return(false); } if (CitizenProxy.IsCollapsed(ref citizen)) { Log.Debug($"{GetCitizenDesc(citizenId, ref citizen)} is collapsed, doing nothing..."); return(false); } return(true); }
/// <summary> /// Ensures that the provided citizen is in a valid state and can be processed. /// </summary> /// /// <param name="citizenId">The citizen ID to check.</param> /// <param name="citizen">The citizen data reference.</param> /// /// <returns><c>true</c> if the provided citizen is in a valid state; otherwise, <c>false</c>.</returns> protected bool EnsureCitizenCanBeProcessed(uint citizenId, ref TCitizen citizen) { if ((CitizenProxy.GetHomeBuilding(ref citizen) == 0 && CitizenProxy.GetWorkBuilding(ref citizen) == 0 && CitizenProxy.GetVisitBuilding(ref citizen) == 0 && CitizenProxy.GetInstance(ref citizen) == 0 && CitizenProxy.GetVehicle(ref citizen) == 0) || (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.MovingIn) && CitizenProxy.GetLocation(ref citizen) == Citizen.Location.Home)) { CitizenMgr.ReleaseCitizen(citizenId); return(false); } if (CitizenProxy.IsCollapsed(ref citizen)) { Log.Debug($"{GetCitizenDesc(citizenId, ref citizen, false)} is collapsed, doing nothing..."); return(false); } return(true); }
private bool CitizenReturnsFromLunch(TAI instance, uint citizenId, ref TCitizen citizen, bool isVirtual) { if (IsLunchHour) { return(false); } ushort workBuilding = CitizenProxy.GetWorkBuilding(ref citizen); if (workBuilding != 0) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} returning from lunch to {workBuilding}"); ReturnFromVisit(instance, citizenId, ref citizen, workBuilding, Citizen.Location.Work, isVirtual); } else { Log.Debug($"WARNING: {GetCitizenDesc(citizenId, ref citizen, isVirtual)} is at lunch but no work building. Teleporting home."); CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home); } return(true); }
private bool CitizenGoesRelaxing(TAI instance, uint citizenId, ref TCitizen citizen, bool isVirtual) { Citizen.AgeGroup citizenAge = CitizenProxy.GetAge(ref citizen); if (!Random.ShouldOccur(GetGoOutChance(citizenAge)) || IsBadWeather(citizenId)) { return(false); } ushort buildingId = CitizenProxy.GetCurrentBuilding(ref citizen); if (buildingId == 0) { return(false); } if (TimeInfo.IsNightTime) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} wanna relax at night"); ushort leisure = MoveToLeisure(instance, citizenId, ref citizen, buildingId, isVirtual); Log.DebugIf(leisure != 0, $"Citizen {citizenId} is heading to leisure building {leisure}"); return(leisure != 0); } if (CitizenProxy.GetWorkBuilding(ref citizen) != 0 && IsWorkDayMorning(citizenAge)) { return(false); } if (!isVirtual) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} wanna relax, heading to an entertainment place"); residentAI.FindVisitPlace(instance, citizenId, buildingId, residentAI.GetEntertainmentReason(instance)); } return(true); }
private ResidentState GetResidentState(ref TCitizen citizen) { ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); ItemClass.Service buildingService = BuildingMgr.GetBuildingService(currentBuilding); if (BuildingMgr.BuildingHasFlags(currentBuilding, Building.Flags.Evacuating) && buildingService != ItemClass.Service.Disaster) { return(ResidentState.Evacuating); } switch (CitizenProxy.GetLocation(ref citizen)) { case Citizen.Location.Home: if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.MovingIn)) { return(ResidentState.LeftCity); } if (currentBuilding != 0) { return(ResidentState.AtHome); } return(ResidentState.Unknown); case Citizen.Location.Work: if (buildingService == ItemClass.Service.Disaster && CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating)) { return(ResidentState.InShelter); } return(currentBuilding != 0 ? ResidentState.AtSchoolOrWork : ResidentState.Unknown); case Citizen.Location.Visit: if (currentBuilding == 0) { return(ResidentState.Unknown); } switch (buildingService) { case ItemClass.Service.Commercial: if (CitizenProxy.GetWorkBuilding(ref citizen) != 0 && IsWorkDay && TimeInfo.CurrentHour > Config.LunchBegin && TimeInfo.CurrentHour < GetSpareTimeBeginHour(CitizenProxy.GetAge(ref citizen))) { return(ResidentState.AtLunch); } if (BuildingMgr.GetBuildingSubService(currentBuilding) == ItemClass.SubService.CommercialLeisure) { return(ResidentState.AtLeisureArea); } return(ResidentState.Shopping); case ItemClass.Service.Beautification: return(ResidentState.AtLeisureArea); case ItemClass.Service.Disaster: return(ResidentState.InShelter); } return(ResidentState.Visiting); case Citizen.Location.Moving: ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen); return(homeBuilding != 0 && CitizenMgr.GetTargetBuilding(CitizenProxy.GetInstance(ref citizen)) == homeBuilding ? ResidentState.MovingHome : ResidentState.MovingToTarget); default: return(ResidentState.Unknown); } }
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); }
private bool UpdateCitizenSchedule(ref CitizenSchedule schedule, uint citizenId, ref TCitizen citizen) { // If the game changed the work building, we have to update the work shifts first ushort workBuilding = CitizenProxy.GetWorkBuilding(ref citizen); if (schedule.WorkBuilding != workBuilding || (workBuilding == 0 && schedule.WorkShift != WorkShift.Unemployed)) { schedule.WorkBuilding = workBuilding; workBehavior.UpdateWorkShift(ref schedule, CitizenProxy.GetAge(ref citizen)); if (schedule.CurrentState == ResidentState.AtSchoolOrWork && schedule.ScheduledStateTime == default) { // When enabling for an existing game, the citizens that are working have no schedule yet schedule.Schedule(ResidentState.Unknown, TimeInfo.Now.FutureHour(schedule.WorkShiftEndHour)); } else if (schedule.WorkBuilding == 0 && (schedule.ScheduledState == ResidentState.AtSchoolOrWork || schedule.WorkStatus == WorkStatus.Working)) { // This is for the case when the citizen becomes unemployed while at work schedule.Schedule(ResidentState.Unknown); } Log.Debug(LogCategory.Schedule, $"Updated work shifts for citizen {citizenId}: work shift {schedule.WorkShift}, {schedule.WorkShiftStartHour} - {schedule.WorkShiftEndHour}, weekends: {schedule.WorksOnWeekends}"); } if (schedule.ScheduledState != ResidentState.Unknown) { return(false); } Log.Debug(LogCategory.Schedule, TimeInfo.Now, $"Scheduling for {GetCitizenDesc(citizenId, ref citizen)}..."); if (schedule.WorkStatus == WorkStatus.Working) { schedule.WorkStatus = WorkStatus.None; } DateTime nextActivityTime = todayWakeUp; if (schedule.CurrentState != ResidentState.AtSchoolOrWork && workBuilding != 0 && schedule.WorkStatus != WorkStatus.OnVacation) { if (ScheduleWork(ref schedule, ref citizen)) { return(true); } if (schedule.ScheduledStateTime > nextActivityTime) { nextActivityTime = schedule.ScheduledStateTime; } } if (ScheduleShopping(ref schedule, ref citizen, false)) { Log.Debug(LogCategory.Schedule, $" - Schedule shopping"); return(true); } if (ScheduleRelaxing(ref schedule, citizenId, ref citizen)) { Log.Debug(LogCategory.Schedule, $" - Schedule relaxing"); return(true); } if (schedule.CurrentState == ResidentState.AtHome) { if (Random.ShouldOccur(StayHomeAllDayChance)) { if (nextActivityTime < TimeInfo.Now) { nextActivityTime = todayWakeUp.FutureHour(Config.WakeUpHour); } } else { nextActivityTime = default; } #if DEBUG if (nextActivityTime <= TimeInfo.Now) { Log.Debug(LogCategory.Schedule, $" - Schedule idle until next scheduling run"); } else { Log.Debug(LogCategory.Schedule, $" - Schedule idle until {nextActivityTime}"); } #endif schedule.Schedule(ResidentState.Unknown, nextActivityTime); } else { Log.Debug(LogCategory.Schedule, $" - Schedule moving home"); schedule.Schedule(ResidentState.AtHome); } return(true); }
// TODO: refactor to decrease cyclomatic complexity private ScheduleAction UpdateCitizenState(ref TCitizen citizen, ref CitizenSchedule schedule) { if (schedule.CurrentState == ResidentState.Ignored) { return(ScheduleAction.Ignore); } if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.DummyTraffic)) { schedule.CurrentState = ResidentState.Ignored; return(ScheduleAction.Ignore); } Citizen.Location location = CitizenProxy.GetLocation(ref citizen); if (location == Citizen.Location.Moving) { if (CitizenMgr.InstanceHasFlags( CitizenProxy.GetInstance(ref citizen), CitizenInstance.Flags.OnTour | CitizenInstance.Flags.TargetIsNode, true)) { // Guided tours are treated as visits schedule.CurrentState = ResidentState.Visiting; schedule.Hint = ScheduleHint.OnTour; return(ScheduleAction.ProcessState); } return(ScheduleAction.ProcessTransition); } ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); if (currentBuilding == 0) { schedule.CurrentState = ResidentState.Unknown; return(ScheduleAction.ProcessState); } ItemClass.Service buildingService = BuildingMgr.GetBuildingService(currentBuilding); if (BuildingMgr.BuildingHasFlags(currentBuilding, Building.Flags.Evacuating) && buildingService != ItemClass.Service.Disaster) { schedule.CurrentState = ResidentState.Evacuation; schedule.Schedule(ResidentState.InShelter); return(ScheduleAction.ProcessState); } switch (location) { case Citizen.Location.Home: schedule.CurrentState = ResidentState.AtHome; return(ScheduleAction.ProcessState); case Citizen.Location.Work: if (buildingService == ItemClass.Service.Disaster && CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating)) { schedule.CurrentState = ResidentState.InShelter; return(ScheduleAction.ProcessState); } if (CitizenProxy.GetVisitBuilding(ref citizen) == currentBuilding && schedule.WorkStatus != WorkStatus.Working) { // A citizen may visit their own work building (e.g. shopping) goto case Citizen.Location.Visit; } schedule.CurrentState = ResidentState.AtSchoolOrWork; return(ScheduleAction.ProcessState); case Citizen.Location.Visit: if (CitizenProxy.GetWorkBuilding(ref citizen) == currentBuilding && schedule.WorkStatus == WorkStatus.Working) { goto case Citizen.Location.Work; } switch (buildingService) { case ItemClass.Service.Beautification: case ItemClass.Service.Monument: case ItemClass.Service.Tourism: case ItemClass.Service.Commercial when BuildingMgr.GetBuildingSubService(currentBuilding) == ItemClass.SubService.CommercialLeisure && schedule.WorkStatus != WorkStatus.Working: schedule.CurrentState = ResidentState.Relaxing; return(ScheduleAction.ProcessState); case ItemClass.Service.Commercial: schedule.CurrentState = ResidentState.Shopping; return(ScheduleAction.ProcessState); case ItemClass.Service.Disaster when CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating): schedule.CurrentState = ResidentState.InShelter; return(ScheduleAction.ProcessState); } schedule.CurrentState = ResidentState.Visiting; return(ScheduleAction.ProcessState); } return(ScheduleAction.Ignore); }
private void ProcessCitizenMoving(TAI instance, uint citizenId, ref TCitizen citizen, bool mayCancel) { ushort instanceId = CitizenProxy.GetInstance(ref citizen); ushort vehicleId = CitizenProxy.GetVehicle(ref citizen); if (vehicleId == 0 && instanceId == 0) { if (CitizenProxy.GetVisitBuilding(ref citizen) != 0) { CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0); } if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.MovingIn)) { CitizenMgr.ReleaseCitizen(citizenId); } else { // TODO: check whether this makes sense and maybe remove/replace this logic // Don't know why the original game does this... CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home); CitizenProxy.SetArrested(ref citizen, false); } return; } if (vehicleId == 0 && CitizenMgr.IsAreaEvacuating(instanceId) && !CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating)) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, false)} was on the way, but the area evacuates. Finding an evacuation place."); TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, residentAI.GetEvacuationReason(instance, 0)); return; } bool returnHome = false; ushort targetBuilding = CitizenMgr.GetTargetBuilding(instanceId); if (targetBuilding != CitizenProxy.GetWorkBuilding(ref citizen)) { ItemClass.Service targetService = BuildingMgr.GetBuildingService(targetBuilding); if (targetService == ItemClass.Service.Beautification && IsBadWeather(citizenId)) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, false)} cancels the trip to a park due to bad weather"); returnHome = true; } } if (!returnHome && CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.WaitingTransport | CitizenInstance.Flags.WaitingTaxi)) { if (mayCancel && CitizenMgr.GetInstanceWaitCounter(instanceId) == 255 && Random.ShouldOccur(AbandonTransportWaitChance)) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, false)} goes back home"); returnHome = true; } } if (returnHome) { ushort home = CitizenProxy.GetHomeBuilding(ref citizen); if (home == 0) { return; } residentAI.StartMoving(instance, citizenId, ref citizen, 0, home); } }
protected string GetCitizenDesc(uint citizenId, ref TCitizen citizen) { string employment = CitizenProxy.GetWorkBuilding(ref citizen) == 0 ? "unempl." : "empl."; return($"Citizen {citizenId} ({employment}, {CitizenProxy.GetAge(ref citizen)})"); }
private ResidentState GetResidentState(ref TCitizen citizen) { if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.DummyTraffic)) { return(ResidentState.Ignored); } ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); ItemClass.Service buildingService = BuildingMgr.GetBuildingService(currentBuilding); if (BuildingMgr.BuildingHasFlags(currentBuilding, Building.Flags.Evacuating) && buildingService != ItemClass.Service.Disaster) { return(ResidentState.Evacuating); } switch (CitizenProxy.GetLocation(ref citizen)) { case Citizen.Location.Home: return(currentBuilding != 0 ? ResidentState.AtHome : ResidentState.Unknown); case Citizen.Location.Work: if (buildingService == ItemClass.Service.Disaster && CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating)) { return(ResidentState.InShelter); } if (CitizenProxy.GetVisitBuilding(ref citizen) == currentBuilding) { // A citizen may visit their own work building (e.g. shopping) goto case Citizen.Location.Visit; } return(currentBuilding != 0 ? ResidentState.AtSchoolOrWork : ResidentState.Unknown); case Citizen.Location.Visit: if (currentBuilding == 0) { return(ResidentState.Unknown); } switch (buildingService) { case ItemClass.Service.Commercial: if (CitizenProxy.GetWorkBuilding(ref citizen) != 0 && IsWorkDay && TimeInfo.CurrentHour > Config.LunchBegin && TimeInfo.CurrentHour < GetSpareTimeBeginHour(CitizenProxy.GetAge(ref citizen))) { return(ResidentState.AtLunch); } if (BuildingMgr.GetBuildingSubService(currentBuilding) == ItemClass.SubService.CommercialLeisure) { return(ResidentState.AtLeisureArea); } return(ResidentState.Shopping); case ItemClass.Service.Beautification: return(ResidentState.AtLeisureArea); case ItemClass.Service.Disaster: return(ResidentState.InShelter); } return(ResidentState.Visiting); case Citizen.Location.Moving: ushort instanceId = CitizenProxy.GetInstance(ref citizen); if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.OnTour | CitizenInstance.Flags.TargetIsNode, true)) { return(ResidentState.OnTour); } ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen); return(homeBuilding != 0 && CitizenMgr.GetTargetBuilding(instanceId) == homeBuilding ? ResidentState.MovingHome : ResidentState.MovingToTarget); default: return(ResidentState.Unknown); } }