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 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 void FindRandomVisitPlace(TAI instance, uint citizenId, ref TCitizen citizen, int doNothingProbability, ushort currentBuilding) { int targetType = touristAI.GetRandomTargetType(instance, doNothingProbability); if (targetType == 1) { Log.Debug(TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} decides to leave the city"); touristAI.FindVisitPlace(instance, citizenId, currentBuilding, touristAI.GetLeavingReason(instance, citizenId, ref citizen)); return; } uint goOutChance = spareTimeBehavior.GetGoOutChance( CitizenProxy.GetAge(ref citizen), WorkShift.Unemployed, CitizenProxy.HasFlags(ref citizen, Citizen.Flags.NeedGoods)); if (!Random.ShouldOccur(goOutChance) || IsBadWeather()) { FindHotel(instance, citizenId, ref citizen); return; } switch (targetType) { case 2: touristAI.FindVisitPlace(instance, citizenId, currentBuilding, touristAI.GetShoppingReason(instance)); Log.Debug(TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} stays in the city, goes shopping"); break; case 3: Log.Debug(TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen)} stays in the city, goes relaxing"); touristAI.FindVisitPlace(instance, citizenId, currentBuilding, touristAI.GetEntertainmentReason(instance)); break; } }
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 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 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 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 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 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 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 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); }
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; } }
/// <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)}"); }
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 CanAttendEvent(uint citizenId, ref TCitizen citizen, ICityEvent cityEvent) { Citizen.AgeGroup age = CitizenProxy.GetAge(ref citizen); Citizen.Gender gender = CitizenProxy.GetGender(citizenId); Citizen.Education education = CitizenProxy.GetEducationLevel(ref citizen); Citizen.Wealth wealth = CitizenProxy.GetWealthLevel(ref citizen); Citizen.Wellbeing wellbeing = CitizenProxy.GetWellbeingLevel(ref citizen); Citizen.Happiness happiness = CitizenProxy.GetHappinessLevel(ref citizen); return(cityEvent.TryAcceptAttendee(age, gender, education, wealth, wellbeing, happiness, Random)); }
/// <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 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)); } }
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 void UpdateSickStateOnVisitingHealthcare(uint citizenId, ushort buildingId, ref TCitizen citizen) { var citizenAge = CitizenProxy.GetAge(ref citizen); if ((citizenAge == Citizen.AgeGroup.Child || citizenAge == Citizen.AgeGroup.Teen) && BuildingMgr.IsBuildingAIOfType <ChildcareAI>(buildingId) || citizenAge == Citizen.AgeGroup.Senior && BuildingMgr.IsBuildingAIOfType <EldercareAI>(buildingId)) { if (CitizenProxy.GetHealth(ref citizen) > Random.GetRandomValue(100u)) { Log.Debug(LogCategory.State, TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} was sick, but got healed in a child or elder care building"); CitizenProxy.SetSick(ref citizen, isSick: false); } } }
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 bool CitizenGoesToEvent(TAI instance, uint citizenId, ref TCitizen citizen) { if (!IsChance(GetGoOutChance(CitizenProxy.GetAge(ref citizen)))) { return(false); } if (!AttendUpcomingEvent(citizenId, ref citizen, out ushort buildingId)) { return(false); } Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen)} wanna attend an event at '{buildingId}', on the way now."); return(StartMovingToVisitBuilding(instance, citizenId, ref citizen, buildingId)); }
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 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 uint AdjustRelaxChance(uint relaxChance, ref TCitizen citizen) { ushort visitBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); if (BuildingMgr.GetBuildingSubService(visitBuilding) == ItemClass.SubService.BeautificationParks) { return(relaxChance * 2); } else if (CitizenProxy.GetAge(ref citizen) == Citizen.AgeGroup.Senior && BuildingMgr.IsBuildingServiceLevel(visitBuilding, ItemClass.Service.HealthCare, ItemClass.Level.Level3)) { return(relaxChance * 4); } else { return(relaxChance); } }
private uint GetTouristGoingOutChance(ref TCitizen citizen, TouristTarget target) { Citizen.AgeGroup age = CitizenProxy.GetAge(ref citizen); switch (target) { case TouristTarget.Shopping: return(spareTimeBehavior.GetShoppingChance(age)); case TouristTarget.Relaxing when WeatherInfo.IsBadWeather: return(0u); case TouristTarget.Party: case TouristTarget.Relaxing: return(spareTimeBehavior.GetRelaxingChance(age)); default: return(100u); } }
private void FindRandomVisitPlace(TAI instance, uint citizenId, ref TCitizen citizen, int doNothingProbability, ushort currentBuilding, bool isVirtual) { int targetType = touristAI.GetRandomTargetType(instance, doNothingProbability); if (targetType == 1) { Log.Debug(TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen, isVirtual)} decides to leave the city"); touristAI.FindVisitPlace(instance, citizenId, currentBuilding, touristAI.GetLeavingReason(instance, citizenId, ref citizen)); return; } if (!Random.ShouldOccur(GetGoOutChance(CitizenProxy.GetAge(ref citizen))) || IsBadWeather(citizenId)) { FindHotel(instance, citizenId, ref citizen, isVirtual); return; } if (isVirtual) { if (Random.ShouldOccur(TouristShoppingChance) && BuildingMgr.GetBuildingService(currentBuilding) == ItemClass.Service.Commercial) { BuildingMgr.ModifyMaterialBuffer(currentBuilding, TransferManager.TransferReason.Shopping, -ShoppingGoodsAmount); } touristAI.AddTouristVisit(instance, citizenId, currentBuilding); return; } switch (targetType) { case 2: touristAI.FindVisitPlace(instance, citizenId, currentBuilding, touristAI.GetShoppingReason(instance)); Log.Debug(TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen, isVirtual)} stays in the city, goes shopping"); break; case 3: Log.Debug(TimeInfo.Now, $"Tourist {GetCitizenDesc(citizenId, ref citizen, isVirtual)} stays in the city, goes relaxing"); touristAI.FindVisitPlace(instance, citizenId, currentBuilding, touristAI.GetEntertainmentReason(instance)); break; } }
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 void DoScheduledLunch(ref CitizenSchedule schedule, TAI instance, uint citizenId, ref TCitizen citizen) { ushort currentBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); #if DEBUG string citizenDesc = GetCitizenDesc(citizenId, ref citizen); #else string citizenDesc = null; #endif ushort lunchPlace = MoveToCommercialBuilding(instance, citizenId, ref citizen, LocalSearchDistance); if (lunchPlace != 0) { Log.Debug(TimeInfo.Now, $"{citizenDesc} is going for lunch from {currentBuilding} to {lunchPlace}"); workBehavior.ScheduleReturnFromLunch(ref schedule); } else { Log.Debug(TimeInfo.Now, $"{citizenDesc} wanted to go for lunch from {currentBuilding}, but there were no buildings close enough"); workBehavior.ScheduleReturnFromWork(ref schedule, CitizenProxy.GetAge(ref citizen)); } }