示例#1
0
 def _close_business(self, play_sound=True):
     if not self._is_open:
         return
     if play_sound:
         sound = PlaySound(services.get_active_sim(), self.tuning_data.audio_sting_close.instance)
         sound.start()
     self._employee_manager.close_business()
     self.send_daily_profit_and_cost_update()
     self._send_business_closed_telemetry()
     if self._owner_household_id is not None:
         owner_household = services.household_manager().get(self._owner_household_id)
         owner_household.bucks_tracker.deactivate_all_temporary_perk_timers_of_type(self.tuning_data.bucks)
         self.modify_funds(-self._employee_manager.final_daily_wages(), from_item_sold=False)
     self.on_store_closed()
     services.get_event_manager().process_event(TestEvent.BusinessClosed)
     self._distribute_business_open_status(False)
     if self.business_zone_id == services.current_zone_id():
         self.tuning_data.lighting_helper_close.execute_lighting_helper(self)
         zone_director = services.venue_service().get_zone_director()
         if zone_director is not None:
             zone_director.refresh_open_street_director_status()
     else:
         self.run_off_lot_simulation()
         self._last_off_lot_update = None
     self._is_open = False
     self.show_summary_dialog(is_from_close=True)
     self._open_time = None
 def play_sound(self, target_object):
     if self._sound is None:
         return
     sound = PlaySound(target_object, self._sound.instance)
     sound.start()
     self.apply_audio_effect(target_object)
     return sound
 def play_looping_music_track(self, target_object):
     if self._music_track_snippet is None:
         return
     sound = PlaySound(target_object,
                       self._music_track_snippet.looping_audio.instance)
     sound.start()
     self.apply_audio_effect(target_object)
     return sound
示例#4
0
 def _create_sound_alarm(self, *args, **kwargs):
     track_length = self._get_track_length()
     if self._sound_alarm is None:
         self._sound_alarm = alarms.add_alarm(self, track_length,
                                              self._sound_alarm_callback)
     if self._sound is None:
         self._sound = PlaySound(self._instrument,
                                 self._track.music_clip.instance)
     self._sound.start()
 def _create_sound_alarm(self, *args, **kwargs):
     track_length = self._get_track_length()
     if self._sound_alarm is None:
         self._sound_alarm = alarms.add_alarm(self, track_length, self._sound_alarm_callback)
     if self._sound is None:
         self._sound = PlaySound(self._instrument, self._track.music_clip.instance)
     self._sound.start()
示例#6
0
 def _open_business(self):
     self._show_appropriate_open_business_notification()
     self._clear_state()
     self._is_open = True
     self._open_time = services.time_service().sim_now
     self._employee_manager.open_business()
     if self._owner_household_id is not None:
         owner_household = services.household_manager().get(self.owner_household_id)
         owner_household.bucks_tracker.activate_stored_temporary_perk_timers_of_type(self.tuning_data.bucks)
     self._distribute_business_open_status(is_open=True, open_time=self._open_time.absolute_ticks())
     if self.business_zone_id == services.current_zone_id():
         self.tuning_data.lighting_helper_open.execute_lighting_helper(self)
         zone_director = services.venue_service().get_zone_director()
         zone_director.set_customers_allowed(True)
         zone_director.refresh_open_street_director_status()
     else:
         self.start_off_lot_simulation_time()
     sound = PlaySound(services.get_active_sim(), self.tuning_data.audio_sting_open.instance)
     sound.start()
     self.send_daily_profit_and_cost_update()
     self._send_daily_items_sold_update()
     self._send_review_update_message()
示例#7
0
 def _create_sound_alarm(self, event_data, *args, **kwargs):
     if event_data is not None and event_data.event_data[
             'event_actor_id'] != self.sim.id:
         return
     if self._track is None:
         logger.error('Could not find a music track to play for {}',
                      self,
                      owner='rmccord')
         return
     track_length = self._get_track_length()
     if self._sound_alarm is None:
         self._sound_alarm = alarms.add_alarm(self, track_length,
                                              self._sound_alarm_callback)
     if self._sound is None and self._track.music_clip is not None:
         instrument = self._get_instrument()
         if instrument is not None:
             self._sound = PlaySound(instrument,
                                     self._track.music_clip.instance)
             self._sound.start()
         else:
             logger.error('Instrument is None for participant {} in {}',
                          self.instrument_participant,
                          self,
                          owner='rmccord')
     mouthpiece_target = None if self.mouthpiece_target is None else self.get_participant(
         self.mouthpiece_target)
     for (musician, vocal_track) in self._musicians_and_vocals_gen():
         interaction = None
         if musician.is_sim and musician is not self.sim and mouthpiece_target is not None:
             interaction = self._get_mouthpiece_interaction(
                 mouthpiece_target, musician)
             if interaction is None:
                 continue
             interaction.set_mouthpiece_owner(self)
             liability = self.get_liability(
                 CANCEL_INTERACTION_ON_EXIT_LIABILITY)
             if liability is None:
                 liability = CancelInteractionsOnExitLiability()
                 self.add_liability(CANCEL_INTERACTION_ON_EXIT_LIABILITY,
                                    liability)
             liability.add_cancel_entry(musician, interaction)
         vocal = PlaySound(musician,
                           vocal_track.vocal_clip.instance,
                           is_vox=True)
         vocal.start()
         self._vocals[musician] = (vocal, interaction)
示例#8
0
class PlayAudioMixin:
    INSTANCE_SUBCLASSES_ONLY = True
    INSTANCE_TUNABLES = {
        'play_multiple_clips':
        Tunable(
            description=
            '\n            If true, the Sim will continue playing until the interaction is\n            cancelled or exit conditions are met. \n            ',
            needs_tuning=False,
            tunable_type=bool,
            default=False),
        'music_styles':
        TunableList(
            description=
            '\n            List of music styles that are available for this interaction.\n            ',
            tunable=MusicStyle.TunableReference(
                description=
                '\n                A music style available for this interaction.\n                ',
                pack_safe=True)),
        'use_buffer':
        Tunable(
            description=
            "\n            If true, this interaction will add the buffer tuned on the music\n            track to the length of the track.  This is tunable because some\n            interactions, like Practice, use shorter audio clips that don't\n            require the buffer.\n            ",
            needs_tuning=False,
            tunable_type=bool,
            default=True),
        'instrument_participant':
        TunableEnumEntry(
            description=
            '\n            The participant that the music will play on.\n            ',
            tunable_type=ParticipantTypeSingle,
            default=ParticipantTypeSingle.Object),
        'audio_start_event':
        Tunable(
            description=
            '\n            The script event to listen for from animation so we know when to\n            start the music and vocals.\n            ',
            tunable_type=int,
            default=100),
        'audio_stop_event':
        Tunable(
            description=
            '\n            The script event to listen for from animation so we know when to\n            stop the music and vocals.\n            ',
            tunable_type=int,
            default=101),
        'mouthpiece_target':
        OptionalTunable(
            description=
            '\n            The participant of mine that mouthpieces must target as their mouthpiece\n            target.  e.g. if they are targeting the actor sim of this interaction, \n            their mouthpiece target would be targetsim, my mouthpiece target \n            would be actor.  If all of us are targeting a certain object then\n            both would be object.\n            ',
            tunable=TunableEnumEntry(
                description=
                '\n                The participant of mine that mouthpieces must target.\n                ',
                tunable_type=ParticipantTypeSingle,
                default=ParticipantTypeSingle.Object))
    }

    def __init__(self,
                 aop,
                 context,
                 track=None,
                 pie_menu_category=None,
                 unlockable_name=None,
                 **kwargs):
        super().__init__(aop, context, **kwargs)
        self._track = track
        self.pie_menu_category = pie_menu_category
        self._unlockable_name = unlockable_name
        self._sound_alarm = None
        self._sound = None
        self._vocals = {}

    def build_basic_content(self, sequence=(), **kwargs):
        self.store_event_handler(self._create_sound_alarm,
                                 self.audio_start_event)
        self.store_event_handler(self._cancel_sound_alarm,
                                 self.audio_stop_event)
        sequence = super().build_basic_content(sequence, **kwargs)
        return build_critical_section_with_finally(
            sequence, self._cancel_sound_alarm_no_data)

    def _get_mouthpiece_interaction(self, mouthpiece_object, sim):
        for interaction in sim.get_all_running_and_queued_interactions():
            if isinstance(interaction, PlayAudioMouthpieceSuperInteraction):
                if not interaction.is_finishing:
                    if interaction.is_mouthpiece_target(mouthpiece_object):
                        return interaction

    def _get_required_sims(self, *args, **kwargs):
        required_sims = super()._get_required_sims(*args, **kwargs)
        mouthpiece_target = None if self.mouthpiece_target is None else self.get_participant(
            self.mouthpiece_target)
        if mouthpiece_target is not None:
            for (musician, _) in self._musicians_and_vocals_gen():
                if self._get_mouthpiece_interaction(mouthpiece_target,
                                                    musician) is not None:
                    required_sims.add(musician)
        return required_sims

    def _create_sound_alarm(self, event_data, *args, **kwargs):
        if event_data is not None and event_data.event_data[
                'event_actor_id'] != self.sim.id:
            return
        if self._track is None:
            logger.error('Could not find a music track to play for {}',
                         self,
                         owner='rmccord')
            return
        track_length = self._get_track_length()
        if self._sound_alarm is None:
            self._sound_alarm = alarms.add_alarm(self, track_length,
                                                 self._sound_alarm_callback)
        if self._sound is None and self._track.music_clip is not None:
            instrument = self._get_instrument()
            if instrument is not None:
                self._sound = PlaySound(instrument,
                                        self._track.music_clip.instance)
                self._sound.start()
            else:
                logger.error('Instrument is None for participant {} in {}',
                             self.instrument_participant,
                             self,
                             owner='rmccord')
        mouthpiece_target = None if self.mouthpiece_target is None else self.get_participant(
            self.mouthpiece_target)
        for (musician, vocal_track) in self._musicians_and_vocals_gen():
            interaction = None
            if musician.is_sim and musician is not self.sim and mouthpiece_target is not None:
                interaction = self._get_mouthpiece_interaction(
                    mouthpiece_target, musician)
                if interaction is None:
                    continue
                interaction.set_mouthpiece_owner(self)
                liability = self.get_liability(
                    CANCEL_INTERACTION_ON_EXIT_LIABILITY)
                if liability is None:
                    liability = CancelInteractionsOnExitLiability()
                    self.add_liability(CANCEL_INTERACTION_ON_EXIT_LIABILITY,
                                       liability)
                liability.add_cancel_entry(musician, interaction)
            vocal = PlaySound(musician,
                              vocal_track.vocal_clip.instance,
                              is_vox=True)
            vocal.start()
            self._vocals[musician] = (vocal, interaction)

    def _sound_alarm_callback(self, handle):
        if self.play_multiple_clips:
            self._cancel_sound_alarm(None)
            styles = self._get_music_styles()
            self._track = PlayAudioMixin._get_next_track(
                styles, self.sim, self.get_resolver())
            self._create_sound_alarm(None)
        else:
            self.cancel(
                FinishingType.NATURAL,
                cancel_reason_msg=
                'Sound alarm triggered and the song finished naturally.')

    def stop_mouthpiece(self, sim):
        if sim in self._vocals:
            (vocal, interaction) = self._vocals.pop(sim)
            vocal.stop()
            if interaction is not None:
                self.get_liability(
                    CANCEL_INTERACTION_ON_EXIT_LIABILITY).remove_cancel_entry(
                        sim, interaction)

    def _cancel_sound_alarm_no_data(self, *args, **kwargs):
        self._cancel_sound_alarm(None)

    def _cancel_sound_alarm(self, event_data, *args, **kwargs):
        if event_data is not None and event_data.event_data[
                'event_actor_id'] != self.sim.id:
            return
        if self._sound_alarm is not None:
            alarms.cancel_alarm(self._sound_alarm)
            self._sound_alarm = None
        if self._sound is not None:
            self._sound.stop()
            self._sound = None
        liability = self.get_liability(CANCEL_INTERACTION_ON_EXIT_LIABILITY)
        for (vocal, interaction) in self._vocals.values():
            vocal.stop()
            if interaction is not None:
                interaction.set_mouthpiece_owner(None)
                liability.remove_cancel_entry(interaction.sim, interaction)
        self._vocals.clear()

    def _get_track_length(self):
        real_seconds = self._track.length
        if self.use_buffer:
            real_seconds += self._track.buffer
        interval = clock.interval_in_real_seconds(real_seconds)
        return interval

    def _get_instrument(self):
        return self.get_participant(self.instrument_participant)

    def _musicians_and_vocals_gen(self):
        resolver = self.get_resolver()
        for (participant_type, vocal_tracks) in self._track.vocals.items():
            for participant in resolver.get_participants(participant_type):
                participant = participant.get_sim_instance(
                    allow_hidden_flags=ALL_HIDDEN_REASONS_EXCEPT_UNINITIALIZED)
                if not isinstance(
                        participant,
                        sims.sim_info.SimInfo) or participant is None:
                    logger.warn('Musician participant {} is None for {}',
                                participant_type,
                                self,
                                owner='rmccord')
                else:
                    for track in vocal_tracks:
                        if track.tests.run_tests(resolver):
                            yield (participant, track)
                            break

    def _get_music_styles(self):
        return self.music_styles

    @staticmethod
    def _get_skill_level(skill_type, sim):
        skill = sim.get_statistic(skill_type, add=False)
        if skill is not None:
            return skill.get_user_value()
        elif skill_type.can_add(sim):
            return skill_type.get_user_value()
        return 0

    @staticmethod
    def _get_next_track(styles, sim, resolver):
        valid_tracks = []
        styles = set(styles)
        for (skill_type,
             level_to_tracks) in MusicStyle.tracks_by_skill.items():
            skill_level = PlayAudioMixin._get_skill_level(skill_type, sim)
            for track in level_to_tracks[skill_level]:
                if not styles & MusicStyle.styles_for_track[track]:
                    continue
                valid_tracks.append(track)
        sim_mood = sim.get_mood()
        valid_mood_tracks = [
            track for track in valid_tracks if sim_mood in track.moods
        ]
        if not valid_mood_tracks and not valid_tracks:
            return
        to_consider = valid_mood_tracks or valid_tracks
        random.shuffle(to_consider)
        for track in to_consider:
            if track.check_for_unlock and sim.sim_info.unlock_tracker is not None and sim.sim_info.unlock_tracker.is_unlocked(
                    track):
                return track
            if not track.check_for_unlock:
                if track.tests.run_tests(resolver):
                    return track

    @classmethod
    def _has_tracks(cls, sim, resolver):
        has_tracker = sim.sim_info.unlock_tracker is not None
        styles = set(cls.music_styles)
        for (skill_type,
             level_to_tracks) in MusicStyle.tracks_by_skill.items():
            skill_level = PlayAudioMixin._get_skill_level(skill_type, sim)
            for track in level_to_tracks[skill_level]:
                if not styles & MusicStyle.styles_for_track[track]:
                    continue
                if track.check_for_unlock and has_tracker and sim.sim_info.unlock_tracker.is_unlocked(
                        track):
                    return True
                if not track.check_for_unlock and track.tests.run_tests(
                        resolver):
                    return True
        return False

    @classmethod
    def _verify_tuning_callback(cls):
        if cls.is_super:
            for affordance in cls._content_sets.all_affordances_gen():
                if isinstance(affordance, PlayAudioMixin):
                    logger.error(
                        '{} references another PlayAudio interaction: {} in its content set. This will not properly work as the clip events will collide with one another.',
                        cls, affordance)
示例#9
0
class PlayAudioSuperInteraction(SuperInteraction):
    __qualname__ = 'PlayAudioSuperInteraction'
    INSTANCE_SUBCLASSES_ONLY = True
    SCRIPT_EVENT_ID_START_AUDIO = 100
    SCRIPT_EVENT_ID_STOP_AUDIO = 101
    INSTANCE_TUNABLES = {
        'play_multiple_clips':
        Tunable(
            description=
            '\n            If true, the Sim will continue playing until the interaction is\n            cancelled or exit conditions are met. \n            ',
            needs_tuning=False,
            tunable_type=bool,
            default=False),
        'music_styles':
        TunableList(
            TunableReference(
                description=
                '\n            Which music styles are available for this interaction.\n            ',
                manager=services.get_instance_manager(
                    sims4.resources.Types.RECIPE),
                class_restrictions=(MusicStyle, ))),
        'use_buffer':
        Tunable(
            description=
            "\n            If true, this interaction will add the buffer tuned on the music\n            track to the length of the track.  This is tunable because some\n            interactions, like Practice, use shorter audio clips that don't\n            require the buffer.\n            ",
            needs_tuning=False,
            tunable_type=bool,
            default=True)
    }

    def __init__(self,
                 aop,
                 context,
                 track=None,
                 pie_menu_category=None,
                 unlockable_name=None,
                 **kwargs):
        super().__init__(aop, context, **kwargs)
        self._track = track
        self.pie_menu_category = pie_menu_category
        self._unlockable_name = unlockable_name
        self._sound_alarm = None
        self._sound = None

    def build_basic_content(self, sequence=(), **kwargs):
        self.animation_context.register_event_handler(
            self._create_sound_alarm,
            handler_id=self.SCRIPT_EVENT_ID_START_AUDIO)
        self.animation_context.register_event_handler(
            self._cancel_sound_alarm,
            handler_id=self.SCRIPT_EVENT_ID_STOP_AUDIO)
        return super().build_basic_content(sequence, **kwargs)

    def on_reset(self):
        self._cancel_sound_alarm()
        super().on_reset()

    def _create_sound_alarm(self, *args, **kwargs):
        track_length = self._get_track_length()
        if self._sound_alarm is None:
            self._sound_alarm = alarms.add_alarm(self, track_length,
                                                 self._sound_alarm_callback)
        if self._sound is None:
            self._sound = PlaySound(self._instrument,
                                    self._track.music_clip.instance)
        self._sound.start()

    def _sound_alarm_callback(self, handle):
        if self.play_multiple_clips:
            self._cancel_sound_alarm()
            if hasattr(self, 'recipe'):
                styles = [self.recipe.music_style]
            else:
                styles = self.music_styles
            self._track = PlayAudioSuperInteraction._get_next_track(
                styles, self.sim, self.get_resolver())
            self._create_sound_alarm()
        else:
            self.cancel(
                FinishingType.NATURAL,
                cancel_reason_msg=
                'Sound alarm triggered and the song finished naturally.')

    def _cancel_sound_alarm(self, *args, **kwargs):
        if self._sound_alarm is not None:
            alarms.cancel_alarm(self._sound_alarm)
            self._sound_alarm = None
        if self._sound is not None:
            self._sound.stop()
            self._sound = None

    def _get_track_length(self):
        real_seconds = self._track.length
        if self.use_buffer:
            real_seconds += self._track.buffer
        interval = clock.interval_in_real_seconds(real_seconds)
        return interval

    @property
    def _instrument(self):
        return self.target

    @staticmethod
    def _get_next_track(styles, sim, resolver):
        valid_tracks = []
        for style in styles:
            for track in style.music_tracks:
                if track.check_for_unlock and sim.sim_info.unlock_tracker.is_unlocked(
                        track):
                    valid_tracks.append(track)
                else:
                    while not track.check_for_unlock and track.tests.run_tests(
                            resolver):
                        valid_tracks.append(track)
        sim_mood = sim.get_mood()
        valid_mood_tracks = tuple(track for track in valid_tracks
                                  if sim_mood in track.moods)
        return random.choice(valid_mood_tracks or valid_tracks)
class PlayAudioSuperInteraction(SuperInteraction):
    __qualname__ = 'PlayAudioSuperInteraction'
    INSTANCE_SUBCLASSES_ONLY = True
    SCRIPT_EVENT_ID_START_AUDIO = 100
    SCRIPT_EVENT_ID_STOP_AUDIO = 101
    INSTANCE_TUNABLES = {'play_multiple_clips': Tunable(description='\n            If true, the Sim will continue playing until the interaction is\n            cancelled or exit conditions are met. \n            ', needs_tuning=False, tunable_type=bool, default=False), 'music_styles': TunableList(TunableReference(description='\n            Which music styles are available for this interaction.\n            ', manager=services.get_instance_manager(sims4.resources.Types.RECIPE), class_restrictions=(MusicStyle,))), 'use_buffer': Tunable(description="\n            If true, this interaction will add the buffer tuned on the music\n            track to the length of the track.  This is tunable because some\n            interactions, like Practice, use shorter audio clips that don't\n            require the buffer.\n            ", needs_tuning=False, tunable_type=bool, default=True)}

    def __init__(self, aop, context, track=None, pie_menu_category=None, unlockable_name=None, **kwargs):
        super().__init__(aop, context, **kwargs)
        self._track = track
        self.pie_menu_category = pie_menu_category
        self._unlockable_name = unlockable_name
        self._sound_alarm = None
        self._sound = None

    def build_basic_content(self, sequence=(), **kwargs):
        self.animation_context.register_event_handler(self._create_sound_alarm, handler_id=self.SCRIPT_EVENT_ID_START_AUDIO)
        self.animation_context.register_event_handler(self._cancel_sound_alarm, handler_id=self.SCRIPT_EVENT_ID_STOP_AUDIO)
        return super().build_basic_content(sequence, **kwargs)

    def on_reset(self):
        self._cancel_sound_alarm()
        super().on_reset()

    def _create_sound_alarm(self, *args, **kwargs):
        track_length = self._get_track_length()
        if self._sound_alarm is None:
            self._sound_alarm = alarms.add_alarm(self, track_length, self._sound_alarm_callback)
        if self._sound is None:
            self._sound = PlaySound(self._instrument, self._track.music_clip.instance)
        self._sound.start()

    def _sound_alarm_callback(self, handle):
        if self.play_multiple_clips:
            self._cancel_sound_alarm()
            if hasattr(self, 'recipe'):
                styles = [self.recipe.music_style]
            else:
                styles = self.music_styles
            self._track = PlayAudioSuperInteraction._get_next_track(styles, self.sim, self.get_resolver())
            self._create_sound_alarm()
        else:
            self.cancel(FinishingType.NATURAL, cancel_reason_msg='Sound alarm triggered and the song finished naturally.')

    def _cancel_sound_alarm(self, *args, **kwargs):
        if self._sound_alarm is not None:
            alarms.cancel_alarm(self._sound_alarm)
            self._sound_alarm = None
        if self._sound is not None:
            self._sound.stop()
            self._sound = None

    def _get_track_length(self):
        real_seconds = self._track.length
        if self.use_buffer:
            real_seconds += self._track.buffer
        interval = clock.interval_in_real_seconds(real_seconds)
        return interval

    @property
    def _instrument(self):
        return self.target

    @staticmethod
    def _get_next_track(styles, sim, resolver):
        valid_tracks = []
        for style in styles:
            for track in style.music_tracks:
                if track.check_for_unlock and sim.sim_info.unlock_tracker.is_unlocked(track):
                    valid_tracks.append(track)
                else:
                    while not track.check_for_unlock and track.tests.run_tests(resolver):
                        valid_tracks.append(track)
        sim_mood = sim.get_mood()
        valid_mood_tracks = tuple(track for track in valid_tracks if sim_mood in track.moods)
        return random.choice(valid_mood_tracks or valid_tracks)