private void CalculateShoppingChance(float currentHour) { float minShoppingChanceEndHour = Math.Min(config.WakeupHour, EarliestWakeUp); float maxShoppingChanceStartHour = Math.Max(config.WorkBegin, config.WakeupHour); if (minShoppingChanceEndHour == maxShoppingChanceStartHour) { minShoppingChanceEndHour = RealTimeMath.Clamp(maxShoppingChanceStartHour - 1f, 2f, maxShoppingChanceStartHour - 1f); } #if DEBUG uint oldChance = shoppingChances[(int)Citizen.AgeGroup.Adult]; #endif float chance; bool isNight; float maxShoppingChanceEndHour = Math.Max(config.GoToSleepUpHour, config.WorkEnd); if (currentHour < minShoppingChanceEndHour) { isNight = true; chance = NightShoppingChance; } else if (currentHour < maxShoppingChanceStartHour) { isNight = true; chance = NightShoppingChance + ((100u - NightShoppingChance) * (currentHour - minShoppingChanceEndHour) / (maxShoppingChanceStartHour - minShoppingChanceEndHour)); } else if (currentHour < maxShoppingChanceEndHour) { isNight = false; chance = 100; } else { isNight = true; chance = NightShoppingChance + ((100u - NightShoppingChance) * (24f - currentHour) / (24f - maxShoppingChanceEndHour)); } uint roundedChance = (uint)Math.Round(chance); shoppingChances[(int)Citizen.AgeGroup.Child] = isNight ? 0u : roundedChance; shoppingChances[(int)Citizen.AgeGroup.Teen] = isNight ? 0u : roundedChance; shoppingChances[(int)Citizen.AgeGroup.Young] = roundedChance; shoppingChances[(int)Citizen.AgeGroup.Adult] = roundedChance; shoppingChances[(int)Citizen.AgeGroup.Senior] = isNight ? (uint)Math.Round(chance * 0.1f) : roundedChance; #if DEBUG if (oldChance != roundedChance) { Log.Debug($"SHOPPING CHANCES for {timeInfo.Now}: child = {shoppingChances[0]}, teen = {shoppingChances[1]}, young = {shoppingChances[2]}, adult = {shoppingChances[3]}, senior = {shoppingChances[4]}"); } #endif }
/// <summary>Gets an estimated travel time (in hours) between two specified buildings.</summary> /// <param name="building1">The ID of the first building.</param> /// <param name="building2">The ID of the second building.</param> /// <returns>An estimated travel time in hours.</returns> public float GetEstimatedTravelTime(ushort building1, ushort building2) { if (building1 == 0 || building2 == 0 || building1 == building2) { return(0); } float distance = buildingManager.GetDistanceBetweenBuildings(building1, building2); return(RealTimeMath.Clamp(distance / OnTheWayDistancePerHour, MinTravelTime, MaxTravelTime)); }
/// <summary>Calculates the chances for the citizens to go out based on the current game time.</summary> public void RefreshGoOutChances() { uint weekdayModifier; if (config.IsWeekendEnabled) { weekdayModifier = timeInfo.Now.IsWeekendTime(12f, config.GoToSleepUpHour) ? 11u : 1u; } else { weekdayModifier = 1u; } float currentHour = timeInfo.CurrentHour; float latestGoOutHour = config.GoToSleepUpHour - simulationCycle; bool isDayTime = currentHour >= config.WakeupHour && currentHour < latestGoOutHour; float timeModifier; if (isDayTime) { timeModifier = RealTimeMath.Clamp(currentHour - config.WakeupHour, 0, 4f); } else { float nightDuration = 24f - (latestGoOutHour - config.WakeupHour); float relativeHour = currentHour - latestGoOutHour; if (relativeHour < 0) { relativeHour += 24f; } timeModifier = 3f / nightDuration * (nightDuration - relativeHour); } uint defaultChance = (uint)((timeModifier + weekdayModifier) * timeModifier); bool dump = chances[(int)Citizen.AgeGroup.Young] != defaultChance; chances[(int)Citizen.AgeGroup.Child] = isDayTime ? defaultChance : 0; chances[(int)Citizen.AgeGroup.Teen] = isDayTime ? defaultChance : 0; chances[(int)Citizen.AgeGroup.Young] = defaultChance; chances[(int)Citizen.AgeGroup.Adult] = defaultChance; chances[(int)Citizen.AgeGroup.Senior] = isDayTime ? defaultChance : 0; if (dump) { Log.Debug($"GO OUT CHANCES for {timeInfo.Now}: child = {chances[0]}, teen = {chances[1]}, young = {chances[2]}, adult = {chances[3]}, senior = {chances[4]}"); } }
private void CalculateDefaultChances(float currentHour, uint weekdayModifier) { float latestGoOutHour = config.GoToSleepUpHour - simulationCycle; bool isDayTime = currentHour >= config.WakeupHour && currentHour < latestGoOutHour; float timeModifier; if (isDayTime) { timeModifier = RealTimeMath.Clamp(currentHour - config.WakeupHour, 0, 4f); } else { float nightDuration = 24f - (latestGoOutHour - config.WakeupHour); float relativeHour = currentHour - latestGoOutHour; if (relativeHour < 0) { relativeHour += 24f; } timeModifier = 3f / nightDuration * (nightDuration - relativeHour); } float chance = (timeModifier + weekdayModifier) * timeModifier; uint roundedChance = (uint)Math.Round(chance); #if DEBUG bool dump = defaultChances[(int)Citizen.AgeGroup.Adult] != roundedChance; #endif defaultChances[(int)Citizen.AgeGroup.Child] = isDayTime ? roundedChance : 0; defaultChances[(int)Citizen.AgeGroup.Teen] = isDayTime ? (uint)Math.Round(chance * 0.9f) : 0; defaultChances[(int)Citizen.AgeGroup.Young] = (uint)Math.Round(chance * 1.3f); defaultChances[(int)Citizen.AgeGroup.Adult] = roundedChance; defaultChances[(int)Citizen.AgeGroup.Senior] = isDayTime ? (uint)Math.Round(chance * 0.8f) : 0; #if DEBUG if (dump) { Log.Debug($"DEFAULT GOING OUT CHANCES for {timeInfo.Now}: child = {defaultChances[0]}, teen = {defaultChances[1]}, young = {defaultChances[2]}, adult = {defaultChances[3]}, senior = {defaultChances[4]}"); } #endif }
/// <summary>Validates this instance and corrects possible invalid property values.</summary> /// <returns>This instance.</returns> public RealTimeConfig Validate() { WakeupHour = RealTimeMath.Clamp(WakeupHour, 4f, 8f); GoToSleepUpHour = RealTimeMath.Clamp(GoToSleepUpHour, 20f, 23.75f); DayTimeSpeed = RealTimeMath.Clamp(DayTimeSpeed, 1u, 7u); NightTimeSpeed = RealTimeMath.Clamp(NightTimeSpeed, 1u, 7u); VirtualCitizens = (VirtualCitizensLevel)RealTimeMath.Clamp((int)VirtualCitizens, (int)VirtualCitizensLevel.None, (int)VirtualCitizensLevel.Many); ConstructionSpeed = RealTimeMath.Clamp(ConstructionSpeed, 0u, 100u); SecondShiftQuota = RealTimeMath.Clamp(SecondShiftQuota, 1u, 25u); NightShiftQuota = RealTimeMath.Clamp(NightShiftQuota, 1u, 25u); LunchQuota = RealTimeMath.Clamp(LunchQuota, 0u, 100u); LocalBuildingSearchQuota = RealTimeMath.Clamp(LocalBuildingSearchQuota, 0u, 100u); OnTimeQuota = RealTimeMath.Clamp(OnTimeQuota, 0u, 100u); EarliestHourEventStartWeekday = RealTimeMath.Clamp(EarliestHourEventStartWeekday, 0f, 23.75f); LatestHourEventStartWeekday = RealTimeMath.Clamp(LatestHourEventStartWeekday, 0f, 23.75f); if (LatestHourEventStartWeekday < EarliestHourEventStartWeekday) { LatestHourEventStartWeekday = EarliestHourEventStartWeekday; } EarliestHourEventStartWeekend = RealTimeMath.Clamp(EarliestHourEventStartWeekend, 0f, 23.75f); LatestHourEventStartWeekend = RealTimeMath.Clamp(LatestHourEventStartWeekend, 0f, 23.75f); if (LatestHourEventStartWeekend < EarliestHourEventStartWeekend) { LatestHourEventStartWeekend = EarliestHourEventStartWeekend; } WorkBegin = RealTimeMath.Clamp(WorkBegin, 4f, 11f); WorkEnd = RealTimeMath.Clamp(WorkEnd, 12f, 20f); LunchBegin = RealTimeMath.Clamp(LunchBegin, 11f, 13f); LunchEnd = RealTimeMath.Clamp(LunchEnd, 13f, 15f); SchoolBegin = RealTimeMath.Clamp(SchoolBegin, 4f, 10f); SchoolEnd = RealTimeMath.Clamp(SchoolEnd, 11f, 16f); MaxOvertime = RealTimeMath.Clamp(MaxOvertime, 0f, 4f); return(this); }