/// <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) || CitizenProxy.IsSick(ref citizen)) { CitizenMgr.ReleaseCitizen(citizenId); return; } switch (CitizenProxy.GetLocation(ref citizen)) { case Citizen.Location.Home: case Citizen.Location.Work: CitizenMgr.ReleaseCitizen(citizenId); break; case Citizen.Location.Visit: ProcessVisit(instance, citizenId, ref citizen); break; case Citizen.Location.Moving: ProcessMoving(instance, citizenId, ref citizen); break; } }
private void ProcessMoving(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) { CitizenMgr.ReleaseCitizen(citizenId); } return; } if (vehicleId == 0 && CitizenMgr.IsAreaEvacuating(instanceId) && !CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating)) { Log.Debug(TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} was on the way, but the area evacuates. Leaving the city."); touristAI.FindVisitPlace(instance, citizenId, CitizenProxy.GetCurrentBuilding(ref citizen), touristAI.GetLeavingReason(instance, citizenId, ref citizen)); return; } if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.TargetIsNode | CitizenInstance.Flags.OnTour, true)) { FindRandomVisitPlace(instance, citizenId, ref citizen, TouristDoNothingProbability, 0); } }
private void ProcessCitizenAtHome(TAI instance, uint citizenId, ref TCitizen citizen) { if (CitizenProxy.GetHomeBuilding(ref citizen) == 0) { Log.Debug($"WARNING: {GetCitizenDesc(citizenId, ref citizen)} is in corrupt state: at home with no home building. Releasing the poor citizen."); CitizenMgr.ReleaseCitizen(citizenId); return; } ushort vehicle = CitizenProxy.GetVehicle(ref citizen); if (vehicle != 0) { Log.Debug(TimeInfo.Now, $"WARNING: {GetCitizenDesc(citizenId, ref citizen)} is at home but vehicle = {vehicle}"); return; } if (CitizenGoesWorking(instance, citizenId, ref citizen)) { return; } if (IsBusyAtHomeInTheMorning(CitizenProxy.GetAge(ref citizen)) || !residentAI.DoRandomMove(instance)) { return; } if (CitizenGoesShopping(instance, citizenId, ref citizen) || CitizenGoesToEvent(instance, citizenId, ref citizen)) { return; } CitizenGoesRelaxing(instance, citizenId, ref citizen); }
private bool CitzenReturnsFromShelter(TAI instance, uint citizenId, ref TCitizen citizen) { ushort visitBuilding = CitizenProxy.GetVisitBuilding(ref citizen); if (BuildingMgr.GetBuildingService(visitBuilding) != ItemClass.Service.Disaster) { return(true); } if (!BuildingMgr.BuildingHasFlags(visitBuilding, Building.Flags.Downgrading)) { return(false); } ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen); if (homeBuilding == 0) { Log.Debug($"WARNING: {GetCitizenDesc(citizenId, ref citizen)} was in a shelter but seems to be homeless. Releasing the citizen."); CitizenMgr.ReleaseCitizen(citizenId); return(true); } Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} returning from evacuation place back home"); ReturnFromVisit(instance, citizenId, ref citizen, homeBuilding); 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 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); }
/// <summary> /// The main 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 <see cref="Citizen"/> reference to process.</param> public void UpdateLocation(TAI instance, uint citizenId, ref TCitizen citizen) { if (!EnsureCitizenValid(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); switch (residentState) { case ResidentState.LeftCity: CitizenMgr.ReleaseCitizen(citizenId); break; case ResidentState.MovingHome: ProcessCitizenMoving(instance, citizenId, ref citizen, false); break; case ResidentState.AtHome: ProcessCitizenAtHome(instance, citizenId, ref citizen); break; case ResidentState.MovingToTarget: ProcessCitizenMoving(instance, citizenId, ref citizen, true); break; case ResidentState.AtSchoolOrWork: ProcessCitizenAtSchoolOrWork(instance, citizenId, ref citizen); break; case ResidentState.AtLunch: case ResidentState.Shopping: case ResidentState.AtLeisureArea: case ResidentState.Visiting: ProcessCitizenVisit(instance, residentState, citizenId, ref citizen); break; case ResidentState.Evacuating: ProcessCitizenEvacuation(instance, citizenId, ref citizen); break; case ResidentState.InShelter: CitzenReturnsFromShelter(instance, citizenId, ref citizen); return; } }
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); }
/// <summary> /// Ensures that the specified 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 specified citizen is in a valid state; otherwise, <c>false</c>.</returns> protected bool EnsureCitizenCanBeProcessed(uint citizenId, ref TCitizen citizen) { if (CitizenProxy.IsEmpty(ref citizen) || 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(LogCategory.State, $"{GetCitizenDesc(citizenId, ref citizen)} is collapsed, doing nothing..."); return(false); } return(true); }
private void ProcessCitizenDead(TAI instance, uint citizenId, ref TCitizen citizen) { ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); Citizen.Location currentLocation = CitizenProxy.GetLocation(ref citizen); switch (currentLocation) { case Citizen.Location.Home when currentBuilding != 0: CitizenProxy.SetWorkplace(ref citizen, citizenId, 0); CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0); break; case Citizen.Location.Work when currentBuilding != 0: CitizenProxy.SetHome(ref citizen, citizenId, 0); CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0); break; case Citizen.Location.Visit when currentBuilding != 0: CitizenProxy.SetHome(ref citizen, citizenId, 0); CitizenProxy.SetWorkplace(ref citizen, citizenId, 0); if (BuildingMgr.GetBuildingService(CitizenProxy.GetVisitBuilding(ref citizen)) == ItemClass.Service.HealthCare) { return; } break; case Citizen.Location.Moving when CitizenProxy.GetVehicle(ref citizen) != 0: CitizenProxy.SetHome(ref citizen, citizenId, 0); CitizenProxy.SetWorkplace(ref citizen, citizenId, 0); CitizenProxy.SetVisitPlace(ref citizen, citizenId, 0); return; default: Log.Debug(LogCategory.State, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is released because of death"); residentSchedules[citizenId] = default; CitizenMgr.ReleaseCitizen(citizenId); return; } residentAI.FindHospital(instance, citizenId, currentBuilding, TransferManager.TransferReason.Dead); Log.Debug(LogCategory.State, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} is dead, body should get serviced"); }
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"); }
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 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); } }
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 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 ProcessMoving(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) { CitizenMgr.ReleaseCitizen(citizenId); } return; } bool isEvacuating = CitizenProxy.HasFlags(ref citizen, Citizen.Flags.Evacuating); if (vehicleId == 0 && !isEvacuating && CitizenMgr.IsAreaEvacuating(instanceId)) { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} was on the way, but the area evacuates. Searching for a shelter."); TransferMgr.AddOutgoingOfferFromCurrentPosition(citizenId, touristAI.GetEvacuationReason(instance, 0)); return; } if (isEvacuating) { return; } if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.TargetIsNode | CitizenInstance.Flags.OnTour, all: true)) { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} exits the guided tour."); FindRandomVisitPlace(instance, citizenId, ref citizen, TouristDoNothingProbability, 0); return; } ushort targetBuildingId = CitizenProxy.GetVisitBuilding(ref citizen); TouristTarget target; if (CitizenMgr.InstanceHasFlags(instanceId, CitizenInstance.Flags.TargetIsNode)) { if (CitizenMgr.GetTargetNode(instanceId) != 0) { target = TouristTarget.Relaxing; } else { return; } } else { if (targetBuildingId == 0) { targetBuildingId = CitizenMgr.GetTargetBuilding(instanceId); } BuildingMgr.GetBuildingService(targetBuildingId, out ItemClass.Service targetService, out ItemClass.SubService targetSubService); switch (targetService) { // Heading to a hotel, no need to change anything case ItemClass.Service.Commercial when targetSubService == ItemClass.SubService.CommercialTourist: return; case ItemClass.Service.Commercial when targetSubService == ItemClass.SubService.CommercialLeisure: target = TouristTarget.Party; break; case ItemClass.Service.Tourism: case ItemClass.Service.Beautification: case ItemClass.Service.Monument: target = TouristTarget.Relaxing; break; case ItemClass.Service.Commercial: target = TouristTarget.Shopping; break; default: return; } } if (GetTouristGoingOutChance(ref citizen, target) > 0) { return; } ushort hotel = FindHotel(targetBuildingId); if (hotel != 0) { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} changes the target and moves to a hotel {hotel} because of time or weather"); StartMovingToVisitBuilding(instance, citizenId, ref citizen, 0, hotel); } else { Log.Debug(LogCategory.Movement, TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} leaves the city because of time or weather"); touristAI.FindVisitPlace(instance, citizenId, 0, touristAI.GetLeavingReason(instance, citizenId, ref citizen)); } }
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 (IsChance(TouristEventChance) && AttendUpcomingEvent(citizenId, ref citizen, out ushort eventBuilding)) { StartMovingToVisitBuilding(instance, citizenId, ref citizen, CitizenProxy.GetCurrentBuilding(ref citizen), eventBuilding); touristAI.AddTouristVisit(instance, citizenId, eventBuilding); Log.Debug(TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} attending an event at {eventBuilding}"); return; } bool doShopping; switch (EventMgr.GetEventState(visitBuilding, DateTime.MaxValue)) { case CityEventState.Ongoing: doShopping = IsChance(TouristShoppingChance); break; case CityEventState.Finished: doShopping = !FindRandomVisitPlace(instance, citizenId, ref citizen, 0, visitBuilding); break; default: doShopping = false; break; } if (doShopping || !FindRandomVisitPlace(instance, citizenId, ref citizen, TouristDoNothingProbability, visitBuilding)) { BuildingMgr.ModifyMaterialBuffer(visitBuilding, TransferManager.TransferReason.Shopping, -ShoppingGoodsAmount); touristAI.AddTouristVisit(instance, citizenId, visitBuilding); } }