Пример #1
0
 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()
Пример #2
0
 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
Пример #3
0
 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
Пример #4
0
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
Пример #5
0
 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
Пример #6
0
 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()
Пример #7
0
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
Пример #10
0
 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)
Пример #11
0
 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
Пример #12
0
 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
Пример #14
0
 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
Пример #15
0
    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
Пример #16
0
 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)
Пример #17
0
 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)
Пример #18
0
    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
Пример #19
0
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
Пример #20
0
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
Пример #21
0
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
Пример #22
0
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
Пример #23
0
 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)
Пример #24
0
def request_weather_forecast(num_days: int = 1, _connection=None):
    services.weather_service().populate_forecasts(num_days)
    return True
Пример #25
0
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
Пример #26
0
def set_temperature_effects_enabled(enabled: bool = True, _connection=None):
    services.weather_service().set_temperature_effects_enabled(enabled)
    return True
Пример #27
0
def set_weather_option(precipitation_type: PrecipitationType,
                       weather_option: WeatherOption,
                       _connection=None):
    services.weather_service().set_weather_option(precipitation_type,
                                                  weather_option)
    return True
Пример #28
0
 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)
Пример #29
0
 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
Пример #30
0
 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)