def _handle_season_content_delayed(self, setup_regional_params=True, trigger_weather=False): self._schedule_season_change() self._send_interpolation_update(mid_season_op=services.time_service( ).sim_now >= self._season_content.midpoint_time) if setup_regional_params: self._setup_regional_seasonal_changes() if trigger_weather: services.weather_service().reset_forecasts()
def _create_weather_transition_element(cls, time, new_transition_data, old_transition_data, key, event_element, previous_event_element, using_new_delay): if event_element is None: value = 0.0 start_time = time rate = 0 else: value = event_element.range.random_float() start_time = time + create_time_span( minutes=event_element.start_delay) rate = event_element.start_rate start_value = services.weather_service().get_weather_element_value( key, time) if value == 0.0 and start_value == 0.0: return using_new_delay if rate != 0: using_new_delay = True old_data = old_transition_data.get(key, None) if old_data is not None and old_data.end_value > value: if previous_event_element is not None: using_new_delay = False start_time = time + create_time_span( minutes=previous_event_element.end_delay) rate = previous_event_element.end_rate else: logger.error( 'Weather transition element: old data end value greater than new value for key {}, but there is no old element\nOld data:{}\nOld event:{}\nNew Event:{}', key, old_data, services.weather_service()._current_event, cls) if rate == 0: if old_transition_data[key].end_value != 0.0: logger.error( "Weather transition element unable to calculate rate, and final destination of existing transition isn't 0" ) end_time = time + create_time_span( minutes=cls.FALLBACK_TRANSITION_TIME) new_transition_data[key] = WeatherElementTuple( start_value, time, 0.0, end_time) else: new_transition_data[key] = old_transition_data[key] return using_new_delay transition_duration = abs(start_value - value) / rate end_time = start_time + create_time_span(minutes=transition_duration) new_transition_data[key] = WeatherElementTuple(start_value, start_time, value, end_time) return using_new_delay
def __call__(self): weather_service = services.weather_service() if weather_service is None: if WeatherType.UNDEFINED in self.weather_types: if self.invert: return TestResult( False, 'No WeatherService: UNDEFINED WeatherType {} is prohibited', tooltip=self.tooltip) if not self.invert: return TestResult( False, "No WeatherService: WeatherType must be UNDEFINED and isn't", tooltip=self.tooltip) elif not self.invert: return TestResult( False, "No WeatherService: WeatherType must be UNDEFINED and isn't", tooltip=self.tooltip) elif weather_service.has_any_weather_type(self.weather_types): if self.invert: return TestResult(False, 'Prohibited weather type found', tooltip=self.tooltip) elif not self.invert: return TestResult(False, 'Required weather type not found.', tooltip=self.tooltip) return TestResult.TRUE
def generate_weather_data_view_data(): weather_service = services.weather_service() weather_data = [] if weather_service is not None: entry = { 'title': 'Current Forecast', 'value': str(weather_service._forecasts[0]) } weather_data.append(entry) entry = { 'title': 'Current Event', 'value': str(weather_service._current_event) } weather_data.append(entry) entry = { 'title': 'Current WeatherTypes', 'value': str(weather_service._current_weather_types) } weather_data.append(entry) for key in weather_service._trans_info: entry = { 'title': 'Element: {}'.format( str(WeatherSeasons_pb2. _SEASONWEATHERINTERPOLATIONMESSAGE_SEASONWEATHERINTERPOLATEDTYPE .values_by_number[key].name)), 'value': str(weather_service.get_weather_element_value(key)) } weather_data.append(entry) return weather_data
def _disable_non_tutorial_functionality(self): services.drama_scheduler_service().set_enabled_state(False) npc_hosted_situation_service = services.npc_hosted_situation_service() if npc_hosted_situation_service is not None: npc_hosted_situation_service.suspend_welcome_wagon() if self._receiver_sim_info is not None: household = self._receiver_sim_info.household if household is not None: household.bills_manager.autopay_bills = True if self._sender_sim_info is not None: if self._receiver_sim_info.age == self._sender_sim_info.age: receiver_age_progress = self._receiver_sim_info.age_progress if receiver_age_progress <= self._sender_sim_info.age_progress: if receiver_age_progress == 0: self._receiver_sim_info.age_progress = 0.1 else: self._sender_sim_info.age_progress = 0 relationship_tracker = self._receiver_sim_info.relationship_tracker sender_id = self._sender_sim_info.sim_id relationship = services.relationship_service().create_relationship(self._receiver_sim_info.sim_id, sender_id) relationship_tracker.add_relationship_score(sender_id, self.friendship_value, RelationshipTrack.FRIENDSHIP_TRACK) relationship_tracker.add_relationship_score(sender_id, self.romance_value, RelationshipTrack.ROMANCE_TRACK) relationship.relationship_track_tracker.set_longterm_tracks_locked(True) weather_service = services.weather_service() if weather_service is not None: weather_service.force_start_weather_event(self.weather_to_force, None) weather_service.update_weather_type(during_load=True) fire_service = services.fire_service if fire_service is not None: fire_service.fire_enabled = False
def is_sun_out(self): region_instance = services.current_region() if region_instance is None or not region_instance.provides_sunlight: return False weather_service = services.weather_service() if weather_service is not None and weather_service.is_shady(): return False return self.is_day_time()
def is_any_rain(_connection=None): if services.weather_service().has_weather_type(WeatherType.AnyRain): sims4.commands.output('True, it is raining', _connection) sims4.commands.automation_output('IsAnyRain; Status:True', _connection) return True sims4.commands.output('False, it is not raining', _connection) sims4.commands.automation_output('IsAnyRain; Status:False', _connection) return False
def get_current_temperature() -> Temperature: """ Retrieve the current temperature. """ from weather.weather_enums import WeatherEffectType, Temperature weather_service = services.weather_service() if weather_service is not None: return Temperature( weather_service.get_weather_element_value( WeatherEffectType.TEMPERATURE, default=Temperature.WARM)) return Temperature.WARM
def get_weather_cloud_type() -> CloudType: """ Retrieve the current cloud type. """ weather_service = services.weather_service() if weather_service is None: return CloudType.CLEAR for cloud_type in CloudType.values: if not weather_service.get_weather_element_value(cloud_type, default=0.0): continue return cloud_type return CloudType.CLEAR
def get_outside_object_score_modification(self): weather_service = services.weather_service() if weather_service is not None: multiplier = weather_service.get_current_precipitation_autonomy_multiplier( self.owner) else: multiplier = 1.0 if self._outside_object_supression is not None: return (self._outside_object_supression.is_not_allowed_outside(), multiplier * self._outside_object_supression.outside_multiplier) return (False, multiplier)
def _stop(self): weather_service = services.weather_service() if weather_service is not None: weather_service.flush_weather_aware_message(self.owner) if self._is_outside is not None: weather_types = set(self.anywhere_loot) if self._is_outside: weather_types.update(self.outside_loot) else: weather_types.update(self.inside_loot) weather_service.deregister_object(self.owner, weather_types) self._is_outside = None
def __call__(self): weather_service = services.weather_service() if weather_service is not None: override_forecast = weather_service.get_override_forecast() else: override_forecast = None if not self.weather_forecasts.test_item(override_forecast): return TestResult( False, "Current override forecast {} doesn't pass white/black list", override_forecast, tooltip=self.tooltip) return TestResult.TRUE
def weather_effects_are_active( weather_effect_types: Iterator[WeatherEffectType]) -> bool: """ Determine if any of the specified weather effects are currently active. """ if not hasattr(services, 'weather_service'): return False weather_service = services.weather_service() if weather_service is None: return False for weather_effect_type in weather_effect_types: if not bool( weather_service.get_weather_element_value( weather_effect_type, default=0.0)): continue return True return False
def _run_weather_fixup(self, reason, outfit_change, resolver): weather_service = services.weather_service() if weather_service is None: return outfit_change sim = self.get_sim_instance(allow_hidden_flags=ALL_HIDDEN_REASONS) if sim is None: return outfit_change weather_outfit_change = weather_service.get_weather_outfit_change( resolver, reason=reason) if weather_outfit_change is None: return outfit_change if not sim.is_outside: return outfit_change elif reason in weather_service.WEATHER_OUFTIT_CHANGE_REASONS_TO_IGNORE: return outfit_change return weather_outfit_change
def weather_effects_are_active(weather_effect_types: Iterator[WeatherEffectType]) -> bool: """weather_effects_are_active(weather_effect_types) Determine if any of the specified weather effects are currently active. :param weather_effect_types: An iterable of weather effects to check for. :type weather_effect_types: Iterator[WeatherEffectType] :return: True, if any of the weathers is active. False, if none of the weathers are active. :rtype: bool """ if not hasattr(services, 'weather_service'): return False weather_service = services.weather_service() if weather_service is None: return False for weather_effect_type in weather_effect_types: if not bool(weather_service.get_weather_element_value(weather_effect_type, default=0.0)): continue return True return False
def end(self): drama_service = services.drama_scheduler_service() drama_service.set_enabled_state(True) if self._receiver_sim_info is not None: household = self._receiver_sim_info.household if household is not None: household.bills_manager.autopay_bills = False if self._sender_sim_info is not None: sim_info = self._sender_sim_info household = self._receiver_sim_info.household if sim_info in household: client = services.client_manager().get_first_client() if not client.set_active_sim_info(self._receiver_sim_info): logger.error('Tutorial Drama node ended without being able to set player sim to active.') client.remove_selectable_sim_info(sim_info) household.remove_sim_info(sim_info) sim_info.transfer_to_hidden_household() relationship = services.relationship_service().create_relationship(self._receiver_sim_info.sim_id, sim_info.sim_id) if relationship is not None: relationship.relationship_track_tracker.set_longterm_tracks_locked(False) npc_hosted_situation_service = services.npc_hosted_situation_service() if npc_hosted_situation_service is not None: npc_hosted_situation_service.resume_welcome_wagon() situation_manager = services.get_zone_situation_manager() if situation_manager is not None: situation = situation_manager.get_situation_by_type(self.situation_to_run) if situation is not None: situation_manager.destroy_situation_by_id(situation.id) weather_service = services.weather_service() if weather_service is not None: weather_service.reset_forecasts() fire_service = services.fire_service if fire_service is not None: fire_service.fire_enabled = True resolver = DoubleSimResolver(self._receiver_sim_info, self._sender_sim_info) for loot_action in self.end_loots: loot_action.apply_to_resolver(resolver) drama_service.complete_node(self.uid)
def strike_terrain(position=None): lightning_strike_tuning = LightningTuning.STRIKE_TERRAIN_TUNING if position is None: (position, routing_surface) = LightningStrike._get_terrain_position_and_routing_surface_for_lightning_strike() if position is None: return else: routing_surface = routing.SurfaceIdentifier(services.current_zone_id(), 0, routing.SurfaceType.SURFACETYPE_WORLD) terrain_point = TerrainPoint.create_for_position_and_orientation(position, routing_surface) lot = services.active_lot() if lot.is_position_on_lot(position): fire_service = services.get_fire_service() fire_service.add_delayed_scorch_mark(position, routing_surface, clock.interval_in_real_seconds(lightning_strike_tuning.scorch_mark_delay)) effect = lightning_strike_tuning.effect_on_lot(None, transform_override=terrain_point.transform) else: effect = lightning_strike_tuning.effect_off_lot(None, transform_override=terrain_point.transform) effect.start_one_shot() broadcaster_request = lightning_strike_tuning.broadcaster(terrain_point) broadcaster_request.start_one_shot() create_tuning = lightning_strike_tuning.create_object_tuning if random.random() < create_tuning.chance: weather_service = services.weather_service() weather_service.create_lightning_collectible_alarm(clock.interval_in_real_seconds(lightning_strike_tuning.scorch_mark_delay), terrain_point.location)
def _setup_environment_settings(self, immediate=False): start_time = services.time_service().sim_now weather_service = services.weather_service() if weather_service is None: _forecast_override_fn = lambda _: None else: resolver = SingleSimResolver(services.active_sim_info()) def _forecast_override_fn(forecast_override_op): forecast = forecast_override_op.weather_forecast weather_service.cross_season_override = forecast is not None if forecast is weather_service.get_override_forecast(): return forecast_override_op.apply_to_resolver(resolver) for narrative in self._active_narratives: override = narrative.environment_override if not override is None: if not override.should_apply(): continue _forecast_override_fn(override.weather_forecast_override) for (param, setting) in override.narrative_environment_params.items(): current_val = self._env_settings.get(param, 0) setting_val = setting.value if current_val == setting_val: continue if immediate: end_time = start_time start_val = end_val = setting_val else: start_val = current_val end_val = setting_val end_time = start_time + create_time_span(minutes=setting.interpolation_time) op = SeasonParameterUpdateOp(param, start_val, start_time, end_val, end_time) Distributor.instance().add_op_with_no_owner(op) self._env_settings[param] = setting_val
def set_season(season:SeasonType, interp_time:int=None, _connection=None): services.season_service().reset_region_season_params() services.season_service().set_season(season, SeasonSetSource.CHEAT, interp_time) if interp_time is None: services.weather_service().reset_forecasts() return True
def shift_season_by_weeks(weeks:int, _connection=None): services.season_service().reset_region_season_params() services.season_service().shift_season_by_weeks(weeks) services.weather_service().reset_forecasts() services.season_service().handle_season_content_updated() return True
def set_season_length(length:SeasonLength, _connection=None): services.season_service().reset_region_season_params() services.season_service().set_season_length(length) services.weather_service().reset_forecasts() services.season_service().handle_season_content_updated() return True
def advance_season(_connection=None): services.season_service().reset_region_season_params() services.season_service().advance_season(SeasonSetSource.CHEAT) services.weather_service().reset_forecasts() return True
def _apply_to_subject_and_target(self, subject, target, resolver): weather_service = services.weather_service() if weather_service is not None: weather_service.set_override_forecast(self.weather_forecast)
def request_weather_forecast(num_days: int = 1, _connection=None): services.weather_service().populate_forecasts(num_days) return True
def start_weather_event(weather_event: TunableInstanceParam( sims4.resources.Types.WEATHER_EVENT), hours: float = None, _connection=None): services.weather_service().start_weather_event(weather_event, hours) return True
def set_temperature_effects_enabled(enabled: bool = True, _connection=None): services.weather_service().set_temperature_effects_enabled(enabled) return True
def set_weather_option(precipitation_type: PrecipitationType, weather_option: WeatherOption, _connection=None): services.weather_service().set_weather_option(precipitation_type, weather_option) return True
def _update_location(self, is_inside_override=False, disabling=False): if disabling: is_outside = None elif is_inside_override: is_outside = False elif self.owner.is_in_inventory(): is_outside = None elif not self._inside_sensitive: is_outside = True else: is_outside = self.owner.is_outside if is_outside == self._is_outside: return if self._location_update_status != WeatherAwareComponent.LocationUpdateStatus.NOT_IN_PROGRESS: self._location_update_status = WeatherAwareComponent.LocationUpdateStatus.PENDING return self._location_update_status = WeatherAwareComponent.LocationUpdateStatus.IN_PROGRESS was_outside = self._is_outside self._is_outside = is_outside recurse = False try: weather_service = services.weather_service() if weather_service is not None: weather_types = weather_service.get_current_weather_types() weather_service.update_weather_aware_message(self.owner) else: weather_types = {WeatherType.UNDEFINED} if self.owner.is_sim: resolver = SingleSimResolver(self.owner.sim_info) else: resolver = SingleObjectResolver(self.owner) if was_outside is not None: if was_outside: self._give_loot(weather_types, self.outside_loot, resolver, False) if weather_service is not None: weather_service.deregister_object( self.owner, self.outside_loot.keys()) else: self._give_loot(weather_types, self.inside_loot, resolver, False) if weather_service is not None: weather_service.deregister_object( self.owner, self.inside_loot.keys()) if is_outside is not None: if is_outside: self._give_loot(weather_types, self.outside_loot, resolver, True) if weather_service is not None: weather_service.register_object( self.owner, self.outside_loot.keys()) weather_service.register_object( self.owner, self.anywhere_loot.keys()) else: self._give_loot(weather_types, self.inside_loot, resolver, True) if weather_service is not None: weather_service.register_object( self.owner, self.inside_loot.keys()) weather_service.register_object( self.owner, self.anywhere_loot.keys()) if was_outside is None: self._give_loot(weather_types, self.anywhere_loot, resolver, True) else: self._give_loot(weather_types, self.anywhere_loot, resolver, False) if weather_service is not None: weather_service.deregister_object( self.owner, self.anywhere_loot.keys()) recurse = self._location_update_status == WeatherAwareComponent.LocationUpdateStatus.PENDING finally: self._location_update_status = WeatherAwareComponent.LocationUpdateStatus.NOT_IN_PROGRESS if recurse: self._update_location(is_inside_override=is_inside_override, disabling=disabling)
def __call__(self): weather_service = services.weather_service() time = services.time_service().sim_now if self.temperature is not None: if weather_service is not None: current_temp = Temperature( weather_service.get_weather_element_value( WeatherEffectType.TEMPERATURE, time=time, default=Temperature.WARM)) else: current_temp = Temperature.WARM if self.temperature.invert: if current_temp in self.temperature.temperature: return TestResult( False, 'Temperature ({}) is an invalid temperature', current_temp, tooltip=self.tooltip) elif current_temp not in self.temperature.temperature: return TestResult( False, 'Temperature ({}) is not a valid temperature', current_temp, tooltip=self.tooltip) if self.cloud_state is not None: if weather_service is None: if self.cloud_state.whitelist and CloudType.PARTLY_CLOUDY not in self.cloud_state.whitelist: return TestResult( False, "Whitelist specified and CloudType.PARTLY_CLOUDY isn't in it", tooltip=self.tooltip) if CloudType.PARTLY_CLOUDY in self.cloud_state.blacklist: return TestResult( False, 'Current cloud type CloudType.PARTLY_CLOUDY is in blacklist', tooltip=self.tooltip) else: if self.cloud_state.whitelist: threshold = self.cloud_state.whitelist_threshold for cloud_type in self.cloud_state.whitelist: if weather_service.get_weather_element_value( cloud_type, time=time) > threshold: break else: return TestResult( False, 'Whitelist specified and no specified cloud type is above the threshold', tooltip=self.tooltip) threshold = self.cloud_state.blacklist_threshold for cloud_type in self.cloud_state.blacklist: if weather_service.get_weather_element_value( cloud_type, time=time) > threshold: return TestResult( False, 'Cloud type {} is in the blacklist and above the threshold', cloud_type, tooltip=self.tooltip) if self.precipitation is not None: precip = self._get_processed_weather_element_value( self.precipitation.precipitation_type, weather_service, time) if precip == 0: if not self.precipitation.zero_is_true: return TestResult(False, 'Must not be 0 precipitation', tooltip=self.tooltip) elif precip not in self.precipitation.range: return TestResult( False, 'Precipitation outside acceptable range, currently: {}', precip, tooltip=self.tooltip) if self.lightning is not None: lightning = self._get_processed_weather_element_value( WeatherEffectType.LIGHTNING, weather_service, time) if lightning == 0: if self.lightning: return TestResult(False, 'Must not be 0 lightning', tooltip=self.tooltip) elif not self.lightning: return TestResult(False, 'Must be 0 lightning', tooltip=self.tooltip) if self.thunder is not None: thunder = self._get_processed_weather_element_value( WeatherEffectType.THUNDER, weather_service, time) if thunder == 0: if self.thunder: return TestResult(False, 'Must not be 0 thundering', tooltip=self.tooltip) elif not self.thunder: return TestResult(False, 'Must be 0 thundering', tooltip=self.tooltip) if self.water_freeze is not None: freeze = self._get_processed_weather_element_value( WeatherEffectType.WATER_FROZEN, weather_service, time) if freeze == 0: if not self.water_freeze.zero_is_true: return TestResult(False, 'Must not be 0 water freeze', tooltip=self.tooltip) elif freeze not in self.water_freeze.range: return TestResult( False, 'Water Freeze outside acceptable range, currently: {}', freeze, tooltip=self.tooltip) if self.wind is not None: wind = self._get_processed_weather_element_value( WeatherEffectType.WIND, weather_service, time) if wind == 0: if not self.wind.zero_is_true: return TestResult(False, 'Must not be 0 wind', tooltip=self.tooltip) elif wind not in self.wind.range: return TestResult( False, 'Wind outside acceptable range, currently: {}', wind, tooltip=self.tooltip) if self.ground_cover is not None: cover = self._get_processed_weather_element_value( self.ground_cover.cover_type, weather_service, time) if cover == 0: if not self.ground_cover.zero_is_true: return TestResult(False, 'Must not be 0 ground cover', tooltip=self.tooltip) elif cover not in self.ground_cover.range: return TestResult( False, 'Ground cover outside acceptable range, currently: {}', cover, tooltip=self.tooltip) return TestResult.TRUE
def get_transition_data(cls, previous_event, old_transition_data, duration): transition_data = {} now = services.time_service().sim_now if previous_event is None: key = int(WeatherEffectType.TEMPERATURE) transition_data[key] = WeatherElementTuple(cls.temperature, now, cls.temperature, now) if cls.precipitation is not None: key = int(cls.precipitation.precipitation_type) value = cls.precipitation.range.random_float() transition_data[key] = WeatherElementTuple( value, now, value, now) for (key, value) in cls.cloud_states.items(): tuple_key = int(key) tuple_value = value.range.random_float() transition_data[tuple_key] = WeatherElementTuple( tuple_value, now, tuple_value, now) if cls.wind is not None: key = int(WeatherEffectType.WIND) value = cls.wind.range.random_float() transition_data[key] = WeatherElementTuple( value, now, value, now) if cls.thunder is not None: key = int(WeatherEffectType.THUNDER) value = cls.thunder.range.random_float() transition_data[key] = WeatherElementTuple( value, now, value, now) if cls.lightning is not None: key = int(WeatherEffectType.LIGHTNING) value = cls.lightning.range.random_float() transition_data[key] = WeatherElementTuple( value, now, value, now) else: key = int(WeatherEffectType.TEMPERATURE) transition_data[key] = WeatherElementTuple(cls.temperature, now, cls.temperature, now) clouds_use_new_delay = None key = int(WeatherEffectType.WIND) clouds_use_new_delay = cls._create_weather_transition_element( now, transition_data, old_transition_data, key, cls.wind, previous_event.wind, clouds_use_new_delay) key = int(WeatherEffectType.THUNDER) clouds_use_new_delay = cls._create_weather_transition_element( now, transition_data, old_transition_data, key, cls.thunder, previous_event.thunder, clouds_use_new_delay) key = int(WeatherEffectType.LIGHTNING) clouds_use_new_delay = cls._create_weather_transition_element( now, transition_data, old_transition_data, key, cls.lightning, previous_event.lightning, clouds_use_new_delay) for precip_type in PrecipitationType: event_element = cls.precipitation previous_event_element = previous_event.precipitation key = int(precip_type) if event_element is not None: if event_element.precipitation_type != key: event_element = None if previous_event_element is not None: if previous_event_element.precipitation_type != key: previous_event_element = None clouds_use_new_delay = cls._create_weather_transition_element( now, transition_data, old_transition_data, key, event_element, previous_event_element, clouds_use_new_delay) old_cloud_set = set(previous_event.cloud_states.keys()) new_cloud_set = set(cls.cloud_states.keys()) followup_cloud_set = old_cloud_set - new_cloud_set longest_end_time = now for (key, data) in cls.cloud_states.items(): new_cloud_type = int(key) if clouds_use_new_delay or key not in old_cloud_set: start_time = now + create_time_span( minutes=data.start_delay) rate = data.start_rate else: old_data = previous_event.cloud_states[key] start_time = now + create_time_span( minutes=old_data.end_delay) rate = old_data.end_rate start_value = services.weather_service( ).get_weather_element_value(new_cloud_type, now) end_value = data.range.random_float() transition_duration = abs(end_value - start_value) / rate if followup_cloud_set: transition_duration = transition_duration / 2 end_time = start_time + create_time_span( minutes=transition_duration) if end_time > longest_end_time: longest_end_time = end_time transition_data[new_cloud_type] = WeatherElementTuple( start_value, start_time, end_value, end_time) for cloudtype in followup_cloud_set: data = previous_event.cloud_states[cloudtype] old_cloud_type = int(cloudtype) start_value = services.weather_service( ).get_weather_element_value(old_cloud_type, now) transition_duration = (start_value - 0) / data.end_rate / 2 end_time = longest_end_time + create_time_span( minutes=transition_duration) transition_data[old_cloud_type] = WeatherElementTuple( start_value, longest_end_time, 0.0, end_time) for cloudtype in CloudType: old_data = old_transition_data.get(int(cloudtype)) if cloudtype not in transition_data.keys(): if old_data is not None: if old_data.end_value != 0.0: logger.error( "Obsolete cloud transition that doesn't end at 0" ) start_value = services.weather_service( ).get_weather_element_value(cloudtype, now) end_time = longest_end_time + create_time_span( minutes=cls.FALLBACK_TRANSITION_TIME) transition_data[int( cloudtype)] = WeatherElementTuple( start_value, longest_end_time, 0.0, end_time) elif old_data.end_time >= now: transition_data[int(cloudtype)] = old_data if duration is None: next_time = DATE_AND_TIME_ZERO else: last_time = now for data in transition_data.values(): if last_time is None: last_time = data.end_time elif data.end_time > last_time: last_time = data.end_time next_time = last_time + create_time_span(hours=duration) return (transition_data, next_time)