private bool StartMovingToVisitBuilding(TAI instance, uint citizenId, ref TCitizen citizen, ushort visitBuilding, bool isVirtual) { if (visitBuilding == 0) { return(false); } ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); if (isVirtual || currentBuilding == visitBuilding) { CitizenProxy.SetVisitPlace(ref citizen, citizenId, visitBuilding); CitizenProxy.SetVisitBuilding(ref citizen, visitBuilding); CitizenProxy.SetLocation(ref citizen, Citizen.Location.Visit); return(true); } else if (residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, visitBuilding)) { CitizenProxy.SetVisitPlace(ref citizen, citizenId, visitBuilding); CitizenProxy.SetVisitBuilding(ref citizen, visitBuilding); return(true); } return(false); }
private bool ProcessCitizenSick(TAI instance, uint citizenId, ref TCitizen citizen) { Citizen.Location currentLocation = CitizenProxy.GetLocation(ref citizen); if (currentLocation == Citizen.Location.Moving) { return(false); } ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); if (currentLocation != Citizen.Location.Home && currentBuilding == 0) { Log.Debug(LogCategory.State, $"Teleporting {GetCitizenDesc(citizenId, ref citizen)} back home because they are sick but no building is specified"); CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home); return(true); } if (currentLocation != Citizen.Location.Home && CitizenProxy.GetVehicle(ref citizen) != 0) { return(true); } if (currentLocation == Citizen.Location.Visit) { ItemClass.Service service = BuildingMgr.GetBuildingService(CitizenProxy.GetVisitBuilding(ref citizen)); if (service == ItemClass.Service.HealthCare || service == ItemClass.Service.Disaster) { return(true); } } Log.Debug(LogCategory.State, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is sick, trying to get to a hospital"); residentAI.FindHospital(instance, citizenId, currentBuilding, TransferManager.TransferReason.Sick); return(true); }
private void ReturnFromVisit( TAI instance, uint citizenId, ref TCitizen citizen, ushort targetBuilding, Citizen.Location targetLocation, bool isVirtual) { if (targetBuilding == 0 || targetLocation == Citizen.Location.Visit || CitizenProxy.GetVehicle(ref citizen) != 0) { return; } ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); CitizenProxy.RemoveFlags(ref citizen, Citizen.Flags.Evacuating); CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0); if (isVirtual || targetBuilding == currentBuilding) { CitizenProxy.SetLocation(ref citizen, targetLocation); } else { residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, targetBuilding); } }
private bool StartMovingToVisitBuilding(TAI instance, uint citizenId, ref TCitizen citizen, ushort visitBuilding) { if (visitBuilding == 0) { return(false); } ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); if (currentBuilding == visitBuilding) { CitizenProxy.SetVisitPlace(ref citizen, citizenId, visitBuilding); CitizenProxy.SetLocation(ref citizen, Citizen.Location.Visit); return(true); } CitizenProxy.SetVisitPlace(ref citizen, citizenId, visitBuilding); if (CitizenProxy.GetVisitBuilding(ref citizen) == 0) { // Building is full and doesn't accept visitors anymore return(false); } if (!residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, visitBuilding)) { CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0); return(false); } return(true); }
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); } else if (residentAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, schedule.WorkBuilding) && 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}"); } }
private void ProcessCitizenVisit(TAI instance, ResidentState citizenState, uint citizenId, ref TCitizen citizen, bool isVirtual) { ushort currentBuilding = CitizenProxy.GetVisitBuilding(ref citizen); if (currentBuilding == 0) { Log.Debug($"WARNING: {GetCitizenDesc(citizenId, ref citizen, isVirtual)} is in corrupt state: visiting with no visit building. Teleporting home."); CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home); return; } switch (citizenState) { case ResidentState.AtLunch: CitizenReturnsFromLunch(instance, citizenId, ref citizen, isVirtual); return; case ResidentState.AtLeisureArea: if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.NeedGoods) && BuildingMgr.GetBuildingSubService(currentBuilding) == ItemClass.SubService.CommercialLeisure) { // No Citizen.Flags.NeedGoods flag reset here, because we only bought 'beer' or 'champagne' in a leisure building. BuildingMgr.ModifyMaterialBuffer(CitizenProxy.GetVisitBuilding(ref citizen), TransferManager.TransferReason.Shopping, -ShoppingGoodsAmount); } goto case ResidentState.Visiting; case ResidentState.Visiting: if (!CitizenGoesWorking(instance, citizenId, ref citizen, isVirtual)) { CitizenReturnsHomeFromVisit(instance, citizenId, ref citizen, isVirtual); } return; case ResidentState.Shopping: if (CitizenProxy.HasFlags(ref citizen, Citizen.Flags.NeedGoods)) { BuildingMgr.ModifyMaterialBuffer(CitizenProxy.GetVisitBuilding(ref citizen), TransferManager.TransferReason.Shopping, -ShoppingGoodsAmount); CitizenProxy.RemoveFlags(ref citizen, Citizen.Flags.NeedGoods); } if (CitizenGoesWorking(instance, citizenId, ref citizen, isVirtual) || CitizenGoesToEvent(instance, citizenId, ref citizen, isVirtual)) { return; } if (Random.ShouldOccur(ReturnFromShoppingChance) || IsWorkDayMorning(CitizenProxy.GetAge(ref citizen))) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} returning from shopping at {currentBuilding} back home"); ReturnFromVisit(instance, citizenId, ref citizen, CitizenProxy.GetHomeBuilding(ref citizen), Citizen.Location.Home, isVirtual); } return; } }
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 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 ProcessCitizenMoving(TAI instance, uint citizenId, ref TCitizen citizen, bool mayCancel) { ushort instanceId = CitizenProxy.GetInstance(ref citizen); ushort vehicleId = CitizenProxy.GetVehicle(ref citizen); // TODO: implement bored of traffic jam trip abandon if (vehicleId == 0 && instanceId == 0) { if (CitizenProxy.GetVisitBuilding(ref citizen) != 0) { CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0); } Log.Debug($"Teleporting {GetCitizenDesc(citizenId, ref citizen)} back home because they are moving but no instance is specified"); 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)} was on the way, but the area evacuates. Finding an evacuation place."); TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, residentAI.GetEvacuationReason(instance, 0)); return; } if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.TargetIsNode | CitizenInstance.Flags.OnTour, true)) { ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen); if (IsChance(AbandonTourChance) && homeBuilding != 0) { CitizenProxy.RemoveFlags(ref citizen, Citizen.Flags.Evacuating); residentAI.StartMoving(instance, citizenId, ref citizen, 0, homeBuilding); } } else if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.WaitingTransport | CitizenInstance.Flags.WaitingTaxi)) { if (mayCancel && CitizenMgr.GetInstanceWaitCounter(instanceId) == 255 && IsChance(AbandonTransportWaitChance)) { ushort home = CitizenProxy.GetHomeBuilding(ref citizen); if (home == 0) { return; } Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} doesn't want to wait for transport anymore, goes back home"); residentAI.StartMoving(instance, citizenId, ref citizen, 0, home); } } }
private void StartMovingToVisitBuilding(TAI instance, uint citizenId, ref TCitizen citizen, ushort currentBuilding, ushort visitBuilding, bool isVirtual) { CitizenProxy.SetVisitPlace(ref citizen, citizenId, visitBuilding); CitizenProxy.SetVisitBuilding(ref citizen, visitBuilding); if (isVirtual) { CitizenProxy.SetLocation(ref citizen, Citizen.Location.Visit); touristAI.AddTouristVisit(instance, citizenId, visitBuilding); } else { touristAI.StartMoving(instance, citizenId, ref citizen, currentBuilding, visitBuilding); } }
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 ProcessCitizenSick(TAI instance, uint citizenId, ref TCitizen citizen) { var currentLocation = CitizenProxy.GetLocation(ref citizen); if (currentLocation == Citizen.Location.Moving) { return(false); } ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); if (currentLocation != Citizen.Location.Home && currentBuilding == 0) { Log.Debug(LogCategory.State, $"Teleporting {GetCitizenDesc(citizenId, ref citizen)} back home because they are sick but no building is specified"); CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home); return(true); } if (currentLocation != Citizen.Location.Home && CitizenProxy.GetVehicle(ref citizen) != 0) { return(true); } if (currentLocation == Citizen.Location.Visit) { ushort visitBuilding = CitizenProxy.GetVisitBuilding(ref citizen); switch (BuildingMgr.GetBuildingService(visitBuilding)) { case ItemClass.Service.HealthCare: UpdateSickStateOnVisitingHealthcare(citizenId, visitBuilding, ref citizen); return(true); case ItemClass.Service.Disaster when !BuildingMgr.BuildingHasFlags(visitBuilding, Building.Flags.Downgrading): return(true); } } Log.Debug(LogCategory.State, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is sick, trying to get to a hospital"); residentAI.FindHospital(instance, citizenId, currentBuilding, TransferManager.TransferReason.Sick); 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 CitizenGoesWorking(TAI instance, uint citizenId, ref TCitizen citizen, bool isVirtual) { ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen); ushort workBuilding = CitizenProxy.GetWorkBuilding(ref citizen); ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); if (!ShouldMoveToSchoolOrWork(citizenId, workBuilding, currentBuilding, CitizenProxy.GetAge(ref citizen))) { return(false); } Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} is going from {currentBuilding} to school/work {workBuilding}"); if (isVirtual) { CitizenProxy.SetLocation(ref citizen, Citizen.Location.Work); } else { residentAI.StartMoving(instance, citizenId, ref citizen, homeBuilding, workBuilding); } return(true); }
/// <summary>The entry method of the custom AI.</summary> /// <param name="instance">A reference to an object instance of the original AI.</param> /// <param name="citizenId">The ID of the citizen to process.</param> /// <param name="citizen">A <typeparamref name="TCitizen"/> reference to process.</param> public void UpdateLocation(TAI instance, uint citizenId, ref TCitizen citizen) { if (!EnsureCitizenCanBeProcessed(citizenId, ref citizen)) { return; } if (CitizenProxy.IsDead(ref citizen)) { ProcessCitizenDead(instance, citizenId, ref citizen); return; } if ((CitizenProxy.IsSick(ref citizen) && ProcessCitizenSick(instance, citizenId, ref citizen)) || (CitizenProxy.IsArrested(ref citizen) && ProcessCitizenArrested(ref citizen))) { return; } ResidentState residentState = GetResidentState(ref citizen); bool isVirtual; switch (residentState) { case ResidentState.MovingHome: ProcessCitizenMoving(instance, citizenId, ref citizen, false); break; case ResidentState.AtHome: isVirtual = IsCitizenVirtual(instance, ref citizen, ShouldRealizeCitizen); ProcessCitizenAtHome(instance, citizenId, ref citizen, isVirtual); break; case ResidentState.MovingToTarget: ProcessCitizenMoving(instance, citizenId, ref citizen, true); break; case ResidentState.AtSchoolOrWork: isVirtual = IsCitizenVirtual(instance, ref citizen, ShouldRealizeCitizen); ProcessCitizenAtSchoolOrWork(instance, citizenId, ref citizen, isVirtual); break; case ResidentState.AtLunch: case ResidentState.Shopping: case ResidentState.AtLeisureArea: case ResidentState.Visiting: isVirtual = IsCitizenVirtual(instance, ref citizen, ShouldRealizeCitizen); ProcessCitizenVisit(instance, residentState, citizenId, ref citizen, isVirtual); break; case ResidentState.OnTour: ProcessCitizenOnTour(instance, citizenId, ref citizen); break; case ResidentState.Evacuating: ProcessCitizenEvacuation(instance, citizenId, ref citizen); break; case ResidentState.InShelter: isVirtual = IsCitizenVirtual(instance, ref citizen, ShouldRealizeCitizen); CitizenReturnsFromShelter(instance, citizenId, ref citizen, isVirtual); break; case ResidentState.Unknown: Log.Debug(TimeInfo.Now, $"WARNING: {GetCitizenDesc(citizenId, ref citizen, null)} is in an UNKNOWN state! Teleporting back home"); if (CitizenProxy.GetHomeBuilding(ref citizen) != 0) { CitizenProxy.SetLocation(ref citizen, Citizen.Location.Home); } break; } }
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 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); } }