private bool IsBuildingNoiseRestricted(ushort targetBuilding, ushort currentBuilding) { if (BuildingMgr.GetBuildingSubService(targetBuilding) != ItemClass.SubService.CommercialLeisure) { return(false); } float currentHour = TimeInfo.CurrentHour; if (currentHour >= Config.GoToSleepUpHour || currentHour <= Config.WakeupHour) { return(BuildingMgr.IsBuildingNoiseRestricted(targetBuilding)); } float travelTime = GetEstimatedTravelTime(currentBuilding, targetBuilding); if (travelTime == 0) { return(false); } float arriveHour = (float)TimeInfo.Now.AddHours(travelTime).TimeOfDay.TotalHours; if (arriveHour >= Config.GoToSleepUpHour || arriveHour <= Config.WakeupHour) { return(BuildingMgr.IsBuildingNoiseRestricted(targetBuilding)); } return(false); }
private bool CitizenReturnsHomeFromVisit(TAI instance, uint citizenId, ref TCitizen citizen, bool isVirtual) { ushort homeBuilding = CitizenProxy.GetHomeBuilding(ref citizen); if (homeBuilding == 0 || CitizenProxy.GetVehicle(ref citizen) != 0) { return(false); } ushort visitBuilding = CitizenProxy.GetVisitBuilding(ref citizen); switch (EventMgr.GetEventState(visitBuilding, TimeInfo.Now.AddHours(MaxHoursOnTheWay))) { case CityEventState.Upcoming: case CityEventState.Ongoing: return(false); case CityEventState.Finished: Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} returning from an event at {visitBuilding} back home to {homeBuilding}"); ReturnFromVisit(instance, citizenId, ref citizen, homeBuilding, Citizen.Location.Home, isVirtual); return(true); } ItemClass.SubService visitedSubService = BuildingMgr.GetBuildingSubService(visitBuilding); if (Random.ShouldOccur(ReturnFromVisitChance) || (visitedSubService == ItemClass.SubService.CommercialLeisure && TimeInfo.IsNightTime && BuildingMgr.IsBuildingNoiseRestricted(visitBuilding))) { Log.Debug(TimeInfo.Now, $"{GetCitizenDesc(citizenId, ref citizen, isVirtual)} returning from visit back home"); ReturnFromVisit(instance, citizenId, ref citizen, homeBuilding, Citizen.Location.Home, isVirtual); return(true); } return(false); }
private uint AdjustRelaxChance(uint relaxChance, ref TCitizen citizen) { ushort visitBuilding = CitizenProxy.GetCurrentBuilding(ref citizen); return((BuildingMgr.GetBuildingSubService(visitBuilding) == ItemClass.SubService.BeautificationParks) ? relaxChance * 2 : relaxChance); }
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 bool ProcessCitizenRelaxing(ref CitizenSchedule schedule, uint citizenId, ref TCitizen citizen) { ushort currentBuilding = CitizenProxy.GetVisitBuilding(ref citizen); 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(currentBuilding, TransferManager.TransferReason.Shopping, -ShoppingGoodsAmount); } return(RescheduleVisit(ref schedule, citizenId, ref citizen, currentBuilding)); }
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 bool ShouldMoveToSchoolOrWork(uint citizenId, ushort workBuilding, ushort currentBuilding, Citizen.AgeGroup citizenAge) { if (workBuilding == 0 || citizenAge == Citizen.AgeGroup.Senior) { return(false); } ItemClass.Service buildingSevice = BuildingMgr.GetBuildingService(workBuilding); ItemClass.SubService buildingSubService = BuildingMgr.GetBuildingSubService(workBuilding); if (IsWeekend && !IsBuildingActiveOnWeekend(buildingSevice, buildingSubService)) { return(false); } if ((citizenId & 0x7FF) == TimeInfo.Now.Day) { Log.Debug(TimeInfo.Now, $"Citizen {citizenId} has a day off work today"); return(false); } if (citizenAge == Citizen.AgeGroup.Child || citizenAge == Citizen.AgeGroup.Teen) { return(ShouldMoveToSchoolOrWork(currentBuilding, workBuilding, Config.SchoolBegin, Config.SchoolEnd, 0)); } GetWorkShiftTimes(citizenId, buildingSevice, buildingSubService, out float workBeginHour, out float workEndHour); if (!CheckMinimumShiftDuration(workBeginHour, workEndHour)) { return(false); } float overtime = Random.ShouldOccur(Config.OnTimeQuota) ? 0 : Config.MaxOvertime * Random.GetRandomValue(100u) / 200f; return(ShouldMoveToSchoolOrWork(currentBuilding, workBuilding, workBeginHour, workEndHour, overtime)); }
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 ShouldReturnFromSchoolOrWork(uint citizenId, ushort buildingId, Citizen.AgeGroup citizenAge) { if (citizenAge == Citizen.AgeGroup.Senior) { return(true); } ItemClass.Service buildingSevice = BuildingMgr.GetBuildingService(buildingId); ItemClass.SubService buildingSubService = BuildingMgr.GetBuildingSubService(buildingId); if (IsWeekend && !IsBuildingActiveOnWeekend(buildingSevice, buildingSubService)) { return(true); } float currentHour = TimeInfo.CurrentHour; if (citizenAge == Citizen.AgeGroup.Child || citizenAge == Citizen.AgeGroup.Teen) { return(currentHour >= Config.SchoolEnd || currentHour < Config.SchoolBegin - MaxHoursOnTheWay); } GetWorkShiftTimes(citizenId, buildingSevice, buildingSubService, out float workBeginHour, out float workEndHour); if (!CheckMinimumShiftDuration(workBeginHour, workEndHour)) { return(true); } float earliestGotoHour = workBeginHour - MaxHoursOnTheWay - Config.MaxOvertime; if (earliestGotoHour < 0) { earliestGotoHour += 24f; } float latestLeaveHour = workEndHour + Config.MaxOvertime; if (latestLeaveHour >= 24f) { latestLeaveHour -= 24f; } if (earliestGotoHour < latestLeaveHour) { if (currentHour >= latestLeaveHour || currentHour < earliestGotoHour) { return(true); } else if (currentHour >= workEndHour) { return(Random.ShouldOccur(Config.OnTimeQuota)); } } else { if (currentHour >= latestLeaveHour && currentHour < earliestGotoHour) { return(true); } else if (currentHour >= workEndHour && currentHour < earliestGotoHour) { return(Random.ShouldOccur(Config.OnTimeQuota)); } } return(false); }
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); } }
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); } }
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); } }