Esempio n. 1
0
class ChaletGardenSituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {
        'man_job_and_role':
        TunableSituationJobAndRoleState(
            description=
            '\n            The job and role state for the man on the Chalet Garden lot.\n            '
        ),
        'woman_job_and_role':
        TunableSituationJobAndRoleState(
            description=
            '\n            The job and role state for the man on the Chalet Garden lot.\n            '
        ),
        'group_filter':
        TunableReference(
            description=
            '\n            The group filter for these Sims. This filter is what will\n            setup the Sims that need to spawn in. They will be added\n            to Individual Sim Situations.\n            ',
            manager=services.get_instance_manager(
                sims4.resources.Types.SIM_FILTER),
            class_restrictions=filters.tunable.TunableAggregateFilter,
            tuning_group=GroupNames.ROLES)
    }
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    @classmethod
    def _states(cls):
        return (SituationStateData(1, _GroupState), )

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.man_job_and_role.job, cls.man_job_and_role.role_state),
                (cls.woman_job_and_role.job, cls.woman_job_and_role.role_state)
                ]

    @classmethod
    def default_job(cls):
        pass

    @classmethod
    def get_predefined_guest_list(cls):
        guest_list = SituationGuestList(invite_only=True)
        worker_filter = cls.group_filter if cls.group_filter is not None else cls.default_job(
        ).filter
        filter_results = services.sim_filter_service().submit_matching_filter(
            sim_filter=worker_filter,
            allow_yielding=False,
            gsi_source_fn=cls.get_sim_filter_gsi_name)
        if not filter_results:
            logger.error('Failed to find/create any sims for {};', cls)
            return guest_list
        for result in filter_results:
            job = cls.man_job_and_role.job if result.sim_info.is_male else cls.woman_job_and_role.job
            guest_list.add_guest_info(
                SituationGuestInfo(result.sim_info.sim_id, job,
                                   RequestSpawningOption.DONT_CARE,
                                   BouncerRequestPriority.BACKGROUND_MEDIUM))
        return guest_list

    def start_situation(self):
        super().start_situation()
        self._change_state(_GroupState())
class StarPlacementCeremonySituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {'honoree_job_and_role_state': TunableSituationJobAndRoleState(description='\n            The job and role state for the honoree.\n            '), 'crowd_member_job_and_role_state': TunableSituationJobAndRoleState(description='\n            The job and role state for a crowd member.\n            '), 'impatient_notification': TunableUiDialogNotificationSnippet(description='\n            The notification that is displayed after the Gather State has timed\n            out.\n            '), 'timed_out_notification': TunableUiDialogNotificationSnippet(description='\n            The notification that is displayed after the Impatient Gather State has timed\n            out.\n            '), 'gather_state': _GatherState.TunableFactory(description='\n            The gather state for the start placement ceremony situation where\n            the crowd gathers around the star. \n            ', display_name='1. Gather State', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP), 'impatient_gather_state': _ImpatientGatherState.TunableFactory(description="\n            The crowd grows restless after they've gathered and the star has not been\n            placed.\n            ", display_name='2. Impatient Gather State', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP), 'start_ceremony_state': _StartCeremonyState.TunableFactory(description='\n            The crowd reacts to the honoree having placed the star, and the honoree\n            responds with an excited reaction, like a fist pump.\n            ', display_name='3. Start Ceremony State', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP)}
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    @classmethod
    def _states(cls):
        return (SituationStateData(1, _GatherState, factory=cls.gather_state), SituationStateData(2, _ImpatientGatherState, factory=cls.impatient_gather_state), SituationStateData(3, _StartCeremonyState, factory=cls.start_ceremony_state))

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.honoree_job_and_role_state.job, cls.honoree_job_and_role_state.role_state), (cls.crowd_member_job_and_role_state.job, cls.crowd_member_job_and_role_state.role_state)]

    @classmethod
    def default_job(cls):
        pass

    def start_situation(self):
        super().start_situation()
        self._change_state(self.gather_state())

    def display_dialog(self, notification):
        active_sim = services.get_active_sim()
        if active_sim is not None:
            dialog = self.impatient_notification(active_sim)
            dialog.show_dialog()
class CafeGenericBackgroundSituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {'generic_sim_job': TunableSituationJobAndRoleState(description="\n            A job and role state that essentially does nothing but filter out\n            Sims that shouldn't be placed in the generic cafe sim situation.\n            "), 'cafe_generic_customer_situation': Situation.TunableReference(description='\n            The individual, generic cafe customer situation we want to use for\n            Sims that show up at the Cafe so they can go get coffee.\n            ', class_restrictions=('CafeGenericCustomerSituation',))}
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    @classmethod
    def _states(cls):
        return (SituationStateData(1, _CafeGenericState),)

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.generic_sim_job.job, cls.generic_sim_job.role_state)]

    @classmethod
    def default_job(cls):
        return cls.generic_sim_job.job

    def start_situation(self):
        super().start_situation()
        self._change_state(_CafeGenericState())

    def _issue_requests(self):
        request = BouncerRequestFactory(self, callback_data=_RequestUserData(role_state_type=self.generic_sim_job.role_state), job_type=self.generic_sim_job.job, request_priority=BouncerRequestPriority.BACKGROUND_MEDIUM, user_facing=False, exclusivity=self.exclusivity)
        self.manager.bouncer.submit_request(request)

    def _on_set_sim_job(self, sim, job_type):
        super()._on_set_sim_job(sim, job_type)
        situation_manager = services.get_zone_situation_manager()
        guest_list = SituationGuestList(invite_only=True)
        guest_info = SituationGuestInfo(sim.sim_info.id, self.cafe_generic_customer_situation.default_job(), RequestSpawningOption.DONT_CARE, BouncerRequestPriority.BACKGROUND_MEDIUM)
        guest_list.add_guest_info(guest_info)
        situation_manager.create_situation(self.cafe_generic_customer_situation, guest_list=guest_list, user_facing=False)
class RoommateSituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {
        'roommate_situation_job_and_role_state':
        TunableSituationJobAndRoleState(
            description=
            '\n            The Situation Job and Role State for the Roommate Sim..\n            ',
            tuning_group=GroupNames.ROLES)
    }
    REMOVE_INSTANCE_TUNABLES = (
        'recommended_job_object_notification', 'recommended_job_object_text',
        'targeted_situation', '_resident_job',
        '_relationship_between_job_members'
    ) + Situation.SITUATION_SCORING_REMOVE_INSTANCE_TUNABLES + Situation.SITUATION_START_FROM_UI_REMOVE_INSTANCE_TUNABLES
    DOES_NOT_CARE_MAX_SCORE = -1

    @classproperty
    def situation_serialization_option(cls):
        return SituationSerializationOption.DONT

    @classmethod
    def _states(cls):
        return (SituationStateData(1, _RoommateSituationState), )

    @classmethod
    def default_job(cls):
        return cls.roommate_situation_job_and_role_state.job

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.roommate_situation_job_and_role_state.job,
                 cls.roommate_situation_job_and_role_state.role_state)]

    def start_situation(self):
        super().start_situation()
        self._change_state(_RoommateSituationState())
Esempio n. 5
0
class SalesTableVendorSituationMixin:
    INSTANCE_TUNABLES = {
        'setup_state':
        SalesTableSetupState.TunableFactory(
            tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP,
            display_name='01_setup_state'),
        'tend_state':
        TendSalesTableState.TunableFactory(
            tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP,
            display_name='02_tend_state'),
        'teardown_state':
        SalesTableTeardownState.TunableFactory(
            tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP,
            display_name='03_teardown_state'),
        'vendor_job_and_role_state':
        TunableSituationJobAndRoleState(
            description=
            '\n            Job and Role State for the vendor.\n            '),
        'sale_object_tags':
        TunableList(
            description=
            '\n            A list of tags that tell us the object comes from the vendor. We\n            use these tags to find objects and destroy them when the situation\n            ends or the sim is removed.\n            ',
            tunable=TunableEnumEntry(
                description=
                '\n                A tag that denotes the object comes from the craft sales vendor\n                and can be destroyed if the situation ends or the sim leaves.\n                ',
                tunable_type=Tag,
                default=Tag.INVALID)),
        'number_of_sale_objects':
        TunableInterval(description='\n            ',
                        tunable_type=int,
                        default_lower=7,
                        default_upper=10,
                        minimum=1,
                        maximum=15)
    }

    @classmethod
    def default_job(cls):
        pass

    @classmethod
    def _states(cls):
        return (SituationStateData(1,
                                   SalesTableSetupState,
                                   factory=cls.setup_state),
                SituationStateData(2,
                                   TendSalesTableState,
                                   factory=cls.tend_state),
                SituationStateData(3,
                                   SalesTableTeardownState,
                                   factory=cls.teardown_state))

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.vendor_job_and_role_state.job,
                 cls.vendor_job_and_role_state.role_state)]

    def start_situation(self):
        super().start_situation()
        self._change_state(self.setup_state())
Esempio n. 6
0
class SimBackgroundSituation(situations.situation_complex.SituationComplexCommon):
    INSTANCE_TUNABLES = {'job_and_role_state': TunableSituationJobAndRoleState(description='\n            The job and role state for the sims\n            ')}
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    @classproperty
    def situation_serialization_option(cls):
        return SituationSerializationOption.DONT

    @classmethod
    def _states(cls):
        return (SituationStateData(1, _SimBackgroundSituationMainState),)

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.job_and_role_state.job, cls.job_and_role_state.role_state)]

    @classmethod
    def default_job(cls):
        pass

    def start_situation(self):
        super().start_situation()
        self._change_state(_SimBackgroundSituationMainState())

    def _issue_requests(self):
        request = BouncerRequestFactory(self, callback_data=_RequestUserData(role_state_type=self.job_and_role_state.role_state), job_type=self.job_and_role_state.job, request_priority=BouncerRequestPriority.BACKGROUND_LOW, user_facing=False, exclusivity=self.exclusivity)
        self.manager.bouncer.submit_request(request)
Esempio n. 7
0
class FanSituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {
        'job_and_role_state':
        TunableSituationJobAndRoleState(
            description=
            '\n            The job and role state for the fan.\n            ')
    }
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    @classmethod
    def _states(cls):
        return (SituationStateData(1, _FanSituationState), )

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.job_and_role_state.job, cls.job_and_role_state.role_state)
                ]

    @classmethod
    def default_job(cls):
        pass

    @classproperty
    def fan_job(cls):
        return cls.job_and_role_state.job

    def start_situation(self):
        super().start_situation()
        self._change_state(_FanSituationState())
Esempio n. 8
0
class PoolVenueLoungerSituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {
        'lounger_job_and_role':
        TunableSituationJobAndRoleState(
            description=
            '\n            The job and role for Pool Venue lounger.\n            '
        )
    }
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    @classmethod
    def _states(cls):
        return (SituationStateData(1, _LoungerSituationState), )

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.lounger_job_and_role.job,
                 cls.lounger_job_and_role.role_state)]

    @classmethod
    def default_job(cls):
        return cls.lounger_job_and_role.job

    def start_situation(self):
        super().start_situation()
        self._change_state(_LoungerSituationState())
Esempio n. 9
0
class SingleSimVisitorSituation(WalkbyLimitingTagsMixin, SituationComplexCommon):
    INSTANCE_TUNABLES = {'visitor_job_and_role': TunableSituationJobAndRoleState(description='\n            The job and role state for the visitor.\n            '), 'has_front_door_arrival_state': _HasFrontDoorArrivalState.TunableFactory(description='\n            The arrival state for the visitor if the lot has a front door.\n            ', display_name='1. Has Front Door Arrival State', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP), 'has_no_front_door_arrival_state': _HasNoFrontDoorArrivalState.TunableFactory(description='\n            The arrival state for the visitor if the lot has a front door.\n            ', display_name='1. Has No Front Door Arrival State', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP), 'visit_state': _VisitState.TunableFactory(description="\n            The state for the visitor to interact with the lot and it's owner.\n            ", display_name='2. Visit State', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP), 'leave_state': _LeaveState.TunableFactory(description='\n            The state for the visitor to leave the lot.\n            ', display_name='3. Leave State', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP)}
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    @classmethod
    def _states(cls):
        return (SituationStateData(1, _HasFrontDoorArrivalState, factory=cls.has_front_door_arrival_state), SituationStateData(2, _HasNoFrontDoorArrivalState, factory=cls.has_no_front_door_arrival_state), SituationStateData(3, _VisitState, factory=cls.visit_state), SituationStateData(4, _LeaveState, factory=cls.leave_state))

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.visitor_job_and_role.job, cls.visitor_job_and_role.role_state)]

    @classmethod
    def default_job(cls):
        pass

    def start_situation(self):
        super().start_situation()
        if services.get_door_service().has_front_door():
            self._change_state(self.has_front_door_arrival_state())
        else:
            self._change_state(self.has_no_front_door_arrival_state())

    @classmethod
    def get_sims_expected_to_be_in_situation(cls):
        return 1

    @property
    def _should_cancel_leave_interaction_on_premature_removal(self):
        return True

    @classproperty
    def situation_serialization_option(cls):
        return situations.situation_types.SituationSerializationOption.OPEN_STREETS
class PartyPooperSituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {
        'party_pooper_state':
        _PartyPooperState.TunableFactory(
            description='\n            ',
            tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP,
            display_name='01_party_pooper_state'),
        'party_pooper_job_and_role':
        TunableSituationJobAndRoleState(
            description=
            '\n            The job and role state for a party pooper.\n            '
        )
    }
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    @classmethod
    def _states(cls):
        return (SituationStateData(1,
                                   _PartyPooperState,
                                   factory=cls.party_pooper_state), )

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.party_pooper_job_and_role.job,
                 cls.party_pooper_job_and_role.role_state)]

    @classmethod
    def default_job(cls):
        return cls.party_pooper_job_and_role.situation_job

    def start_situation(self):
        super().start_situation()
        self._change_state(self.party_pooper_state())
class TendObjectSituation(StaffedObjectSituationMixin, SituationComplexCommon):
    INSTANCE_TUNABLES = {
        'arrive_state':
        ArriveState.TunableFactory(
            description=
            '\n            Situation State for the Sim when they arrive to tend an object.',
            tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP,
            display_name='01_arrive_situation_state'),
        'tend_state':
        TendState.TunableFactory(
            description=
            '\n            Situation State for the Sim to tend an object.\n            ',
            tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP,
            display_name='02_tend_situation_state'),
        'tendor_job_and_role_state':
        TunableSituationJobAndRoleState(
            description=
            '\n            Job and Role State for the tending Sim.\n            '
        )
    }
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    def __init__(self, *arg, **kwargs):
        super().__init__(*arg, **kwargs)
        reader = self._seed.custom_init_params_reader
        if reader is None:
            self._target_id = self._seed.extra_kwargs.get(
                'default_target_id', None)
        else:
            self._target_id = reader.read_uint64(OBJECT_TOKEN, None)
        if self._target_id:
            target = services.object_manager().get(self._target_id)
            if target is not None:
                self._staffed_object = target

    @classmethod
    def default_job(cls):
        pass

    @classmethod
    def _states(cls):
        return (SituationStateData(1, ArriveState, factory=cls.arrive_state),
                SituationStateData(2, TendState, factory=cls.tend_state))

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.tendor_job_and_role_state.job,
                 cls.tendor_job_and_role_state.role_state)]

    def start_situation(self):
        super().start_situation()
        self._change_state(self.arrive_state())

    def _save_custom_situation(self, writer):
        super()._save_custom_situation(writer)
        staffed_object = self.get_staffed_object()
        if staffed_object is not None:
            writer.write_uint64(OBJECT_TOKEN, staffed_object.id)
class CivicInspectorSituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {'inspector_job_and_role_state': TunableSituationJobAndRoleState(description='\n            The job and role state for the eco-inspector.\n            ', tuning_group=GroupNames.ROLES), 'inspector_entry': _InspectorEntryState.TunableFactory(description='\n           Inspector Entry State. Listens for portal allowance.\n            ', display_name='1. Inspector Entry State', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP), 'civic_inspect_outside': _InspectorOutsideState.TunableFactory(description='\n           Inspecting from outside, not allowed inside.\n            ', display_name='2. Civic Inspect Outside', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP), 'civic_inspect_inside': _InspectorInsideState.TunableFactory(description='\n            Allowed inside, but may inspect outside if not objects.\n            ', display_name='3. Civic Inspect Inside', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP), 'final_checks': _FinalChecksState.TunableFactory(description='\n            Checks if civic policy is being followed using the conditions\n            described in tuning. \n            ', display_name='4. Final Checks', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP), 'leave': _LeaveState.TunableFactory(description='\n            Final checks before leaving.\n            ', display_name='5. Leaving state.', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP), 'inspection_successful_notification': UiDialogNotification.TunableFactory(description='\n            A TNS that is displayed to inform of successful inspection.\n            '), 'inspection_failure_notification': UiDialogNotification.TunableFactory(description='\n            A TNS that is displayed to inform of failed inspection.\n            '), 'inspection_partial_success_notification': UiDialogNotification.TunableFactory(description='\n            A TNS that is displayed to inform of failed inspection.\n            '), 'commodity_notfollow': Commodity.TunableReference(description='\n            lot commodity that we set when we want a multiplier for bill modifier.\n                '), 'commodity_follow': Commodity.TunableReference(description='\n            lot commodity that we set when we want a multiplier for bill modifier.\n                '), 'overlook_issues_success_interaction': TunableInteractionOfInterest(description='\n            Interaction pushed to indicate success of overlooking issues.\n            ')}

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.follow_status = PolicyFollowing.FULL_FOLLOWED
        self.policies_not_followed = []

    @classmethod
    def _states(cls):
        return (SituationStateData(1, _WaitState), SituationStateData(2, _InspectorEntryState, factory=cls.inspector_entry), SituationStateData(3, _InspectorInsideState, factory=cls.civic_inspect_inside), SituationStateData(4, _InspectorOutsideState, factory=cls.civic_inspect_outside), SituationStateData(5, _FinalChecksState, factory=cls.final_checks), SituationStateData(6, _LeaveState, factory=cls.leave))

    @classmethod
    def default_job(cls):
        pass

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.inspector_job_and_role_state.job, cls.inspector_job_and_role_state.role_state)]

    def _on_add_sim_to_situation(self, sim, job_type, role_state_type_override=None):
        super()._on_add_sim_to_situation(sim, job_type, role_state_type_override=role_state_type_override)
        if self.inspector_person() is not None:
            self._change_state(self.inspector_entry())

    def _show_inspection_notification(self, inspection_notification, **kwargs):
        inspector = self.inspector_person()
        if inspector is not None:
            dialog = inspection_notification(inspector, resolver=SingleSimResolver(inspector.sim_info))
            dialog.show_dialog(**kwargs)

    def notify_result_and_push_bill_modifier(self):
        lot = services.active_lot()
        additional_tokens = ()
        if self.policies_not_followed:
            additional_tokens = (LocalizationHelperTuning.get_bulleted_list(None, *self.policies_not_followed),)
        if self.follow_status == PolicyFollowing.NOT_FOLLOWED:
            lot.set_stat_value(self.commodity_notfollow, self.commodity_notfollow.max_value_tuning)
            self._show_inspection_notification(self.inspection_failure_notification, additional_tokens=additional_tokens)
        elif self.follow_status == PolicyFollowing.PARTIAL_FOLLOWED:
            self._show_inspection_notification(self.inspection_partial_success_notification, additional_tokens=additional_tokens)
        else:
            lot.set_stat_value(self.commodity_follow, self.commodity_follow.max_value_tuning)
            self._show_inspection_notification(self.inspection_successful_notification)

    def inspector_person(self):
        sim = next(self.all_sims_in_job_gen(self.inspector_job_and_role_state.job), None)
        return sim

    def start_situation(self):
        super().start_situation()
        self._change_state(_WaitState())
class GoDancingBackgroundSituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {
        'generic_sim_job':
        TunableSituationJobAndRoleState(
            description=
            "\n            A job and role state that essentially does nothing but filter out\n            Sims that shouldn't be placed in the party-goer situation.\n            "
        ),
        'party_goer_situation':
        Situation.TunableReference(
            description=
            '\n            The individual, party-goer situation we want to use for\n            Sims that show up at the party so they want to dance and more.\n            ',
            class_restrictions=('GoDancingBackgroundPartyGoerSituation', ))
    }
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    @classmethod
    def _states(cls):
        return (SituationStateData(1, _GoDancingGenericState), )

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.generic_sim_job.job, cls.generic_sim_job.role_state)]

    @classmethod
    def default_job(cls):
        return cls.generic_sim_job.job

    def start_situation(self):
        super().start_situation()
        self._change_state(_GoDancingGenericState())

    def _issue_requests(self):
        request = SelectableSimRequestFactory(
            self,
            callback_data=_RequestUserData(
                role_state_type=self.generic_sim_job.role_state),
            job_type=self.generic_sim_job.job,
            exclusivity=self.exclusivity)
        self.manager.bouncer.submit_request(request)

    def _on_set_sim_job(self, sim, job_type):
        super()._on_set_sim_job(sim, job_type)
        situation_manager = services.get_zone_situation_manager()
        guest_list = SituationGuestList(invite_only=True)
        guest_info = SituationGuestInfo.construct_from_purpose(
            sim.sim_info.id, self.party_goer_situation.default_job(),
            SituationInvitationPurpose.INVITED)
        guest_list.add_guest_info(guest_info)
        situation_manager.create_situation(self.party_goer_situation,
                                           guest_list=guest_list,
                                           user_facing=False)
class NeighborResponseSituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {
        'answer_door_state':
        _AnswerDoorState.TunableFactory(
            description=
            '\n            The situation state for the loud neighbor to answer the door.\n            ',
            tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP,
            display_name='01_answer_door_situation_state'),
        'loud_neighbor_job_and_role_state':
        TunableSituationJobAndRoleState(
            description=
            '\n            The job and role state of the loud neighbor.\n            '
        )
    }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._neighbor_sim = None

    @classproperty
    def allow_user_facing_goals(cls):
        return False

    @classmethod
    def _states(cls):
        return (SituationStateData(1, _WaitForNeighborToSpawnState),
                SituationStateData(2,
                                   _AnswerDoorState,
                                   factory=cls.answer_door_state))

    @classmethod
    def default_job(cls):
        pass

    def _on_set_sim_job(self, sim, job_type):
        super()._on_set_sim_job(sim, job_type)
        self._neighbor_sim = sim
        self._change_state(self.answer_door_state())

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.loud_neighbor_job_and_role_state.job,
                 cls.loud_neighbor_job_and_role_state.role_state)]

    def start_situation(self):
        super().start_situation()
        self._change_state(_WaitForNeighborToSpawnState())
class PaparazziLockOutSituation(
        situations.situation_complex.SituationComplexCommon):
    INSTANCE_TUNABLES = {
        'job_and_role_state':
        TunableSituationJobAndRoleState(
            description=
            '\n            The job and role state for the sims.\n            ')
    }
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    @classproperty
    def situation_serialization_option(cls):
        return SituationSerializationOption.DONT

    @classmethod
    def _states(cls):
        return (SituationStateData(1, _PaparazziLockOutSituationMainState), )

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.job_and_role_state.job, cls.job_and_role_state.role_state)
                ]

    @classmethod
    def default_job(cls):
        pass

    @classmethod
    def get_lock_out_job(cls):
        return cls.job_and_role_state.job

    def start_situation(self):
        super().start_situation()
        self._change_state(_PaparazziLockOutSituationMainState())

    def _issue_requests(self):
        paparazzi_sim_info = next(self._guest_list.invited_sim_infos_gen())
        request = SpecificSimRequestFactory(
            self,
            callback_data=_RequestUserData(
                role_state_type=self.job_and_role_state.role_state),
            job_type=self.job_and_role_state.job,
            request_priority=self.job_and_role_state.role_state.role_priority,
            exclusivity=self.exclusivity,
            sim_id=paparazzi_sim_info.sim_id)
        self.manager.bouncer.submit_request(request)
class UniversityMixerPartySituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {'juice_keg_bearer_job_and_role': TunableSituationJobAndRoleState(description='\n            The job and role state for the bearer of the juice keg.\n            '), 'setup_juice_keg_state': _SetupJuiceKeg.TunableFactory(description='\n            The state to bring in the keg bearer and have the juice keg set up on the lot.\n            ', display_name='1. Setup Juice Keg State', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP), 'mixer_party_state': _MixerParty.TunableFactory(description='\n            The state to represent the party itself.\n            ', display_name='2. Mixer Party State', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP), 'cleanup_party_state': _CleanupJuiceKeg.TunableFactory(description='\n            The state to cleanup the juice keg and end the party\n            ', display_name='3. Party Cleanup State', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP), 'juice_keg_tag': TunableEnumWithFilter(description='\n            Tag used to find the juice keg supplied by the situation.\n            ', tunable_type=Tag, default=Tag.INVALID, invalid_enums=Tag.INVALID, filter_prefixes=('func',))}
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._juice_keg_object_id = None

    def start_situation(self):
        super().start_situation()
        if self.juice_keg is not None:
            self._claim_object(self.juice_keg.id)
        self._change_state(self.setup_juice_keg_state())

    @classmethod
    def _states(cls):
        return (SituationStateData(1, _SetupJuiceKeg, factory=cls.setup_juice_keg_state), SituationStateData(2, _MixerParty, factory=cls.mixer_party_state), SituationStateData(3, _CleanupJuiceKeg, factory=cls.cleanup_party_state))

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.juice_keg_bearer_job_and_role.job, cls.juice_keg_bearer_job_and_role.role_state)]

    @classmethod
    def default_job(cls):
        pass

    @property
    def juice_keg(self):
        object_manager = services.object_manager()
        juice_keg = None
        if self._juice_keg_object_id is not None:
            juice_keg = object_manager.get(self._juice_keg_object_id)
        if juice_keg is None:
            if self.juice_keg_bearer is not None:
                for obj in object_manager.get_objects_with_tag_gen(self.juice_keg_tag):
                    if obj.get_sim_owner_id() is self.juice_keg_bearer.id:
                        juice_keg = obj
                        self._juice_keg_object_id = juice_keg.id
                        break
        return juice_keg

    @property
    def juice_keg_bearer(self):
        sim = next(self.all_sims_in_job_gen(self.juice_keg_bearer_job_and_role.job), None)
        return sim
Esempio n. 17
0
class SuntannerSituation(GiveJobObjectSituationMixin, SituationComplexCommon):
    INSTANCE_TUNABLES = {'situation_default_job_and_role': TunableSituationJobAndRoleState(description='\n            The default job that a visitor will be in during the situation.\n            '), 'default_state': _SuntannerSituationState.TunableFactory(description='\n            The default state of this situation.\n            ', display_name='State', tuning_group=GroupNames.STATE)}
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    @classmethod
    def default_job(cls):
        return cls.situation_default_job_and_role.job

    @classmethod
    def _states(cls):
        return [SituationStateData(1, _SuntannerSituationState, factory=cls.default_state)]

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.situation_default_job_and_role.job, cls.situation_default_job_and_role.role_state)]

    def start_situation(self):
        super().start_situation()
        self._change_state(self.default_state())
Esempio n. 18
0
class GoDancingSituation(SituationZoneDirectorMixin, SituationComplexCommon):
    INSTANCE_TUNABLES = {'party_goer': TunableSituationJobAndRoleState(description='\n            The job and role of Party Goers.\n            '), 'host_job_and_role_state': TunableSituationJobAndRoleState(description='\n            The job and role state of the Sim who planned the Go Dancing\n            Situation.\n            ')}
    REMOVE_INSTANCE_TUNABLES = ('_resident_job',)

    @classproperty
    def allow_user_facing_goals(cls):
        return False

    @classmethod
    def get_possible_zone_ids_for_situation(cls, host_sim_info=None, guest_ids=None):
        possible_zones = super().get_possible_zone_ids_for_situation(host_sim_info=host_sim_info, guest_ids=guest_ids)
        current_zone_id = services.current_zone_id()
        if current_zone_id in possible_zones:
            possible_zones.remove(current_zone_id)
        return possible_zones

    @classmethod
    def _get_zone_director_request_type(cls):
        return ZoneDirectorRequestType.GO_DANCING

    @classmethod
    def _states(cls):
        return (SituationStateData(1, _GoDancingSituationState),)

    @classmethod
    def resident_job(cls):
        return cls.host_job_and_role_state.job

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        party_goer_tuples = [(cls.party_goer.job, cls.party_goer.role_state)]
        host_tuples = [(cls.host_job_and_role_state.job, cls.host_job_and_role_state.role_state)] if cls.resident_job() is not None and cls.host_job_and_role_state.role_state is not None and cls.resident_job() is not cls.party_goer.job else []
        return party_goer_tuples + host_tuples

    @classmethod
    def default_job(cls):
        pass

    def start_situation(self):
        super().start_situation()
        self._change_state(_GoDancingSituationState())
class YardSaleCustomerSituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {
        'browse_items_state':
        BrowseItemsState.TunableFactory(
            tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP,
            display_name='01_browse_items_state'),
        'customer_job_and_role_state':
        TunableSituationJobAndRoleState(
            description=
            '\n            The job and role state for the customer who wants to check out the\n            craft sales table.\n            '
        )
    }

    def __init__(self, *arg, **kwargs):
        super().__init__(*arg, **kwargs)
        self.customer = None

    @classmethod
    def default_job(cls):
        pass

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.customer_job_and_role_state.job,
                 cls.customer_job_and_role_state.role_state)]

    def _on_set_sim_job(self, sim, job_type):
        super()._on_set_sim_job(sim, job_type)
        self.customer = sim

    @classmethod
    def _states(cls):
        return (SituationStateData(1,
                                   BrowseItemsState,
                                   factory=cls.browse_items_state), )

    def start_situation(self):
        super().start_situation()
        self._change_state(self.browse_items_state())

    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES
Esempio n. 20
0
class BarflySituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {
        'barfly_job_and_role':
        TunableSituationJobAndRoleState(
            description=
            '\n            The job and role of the barfly.\n            '),
        'starting_entitlement':
        OptionalTunable(
            description=
            '\n            If enabled, this situation is locked by an entitlement. Otherwise,\n            this situation is available to all players.\n            ',
            tunable=TunableEnumEntry(
                description=
                '\n                Pack required for this event to start.\n                ',
                tunable_type=Pack,
                default=Pack.BASE_GAME))
    }
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    @classmethod
    def _states(cls):
        return (SituationStateData(1, _BarflySituationState), )

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.barfly_job_and_role.job,
                 cls.barfly_job_and_role.role_state)]

    @classmethod
    def default_job(cls):
        pass

    @classmethod
    def situation_meets_starting_requirements(cls, **kwargs):
        if cls.starting_entitlement is None:
            return True
        return is_available_pack(cls.starting_entitlement)

    def start_situation(self):
        super().start_situation()
        self._change_state(_BarflySituationState())
class SelectableSimBackgroundSituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {
        'job_and_role':
        TunableSituationJobAndRoleState(
            description=
            '\n            The job and role that the selectable Sims will be given.\n            '
        )
    }
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    @classproperty
    def situation_serialization_option(cls):
        return SituationSerializationOption.DONT

    @classmethod
    def _states(cls):
        return (SituationStateData(1,
                                   _SelectableSimsBackgroundSituationState), )

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.job_and_role.job, cls.job_and_role.role_state)]

    @classmethod
    def default_job(cls):
        pass

    def start_situation(self):
        super().start_situation()
        self._change_state(_SelectableSimsBackgroundSituationState())

    def _issue_requests(self):
        request = SelectableSimRequestFactory(
            self,
            callback_data=_RequestUserData(
                role_state_type=self.job_and_role.role_state),
            job_type=self.job_and_role.job,
            exclusivity=self.exclusivity)
        self.manager.bouncer.submit_request(request)
Esempio n. 22
0
class KaraokeDuetSimSituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {
        'karaoke_singer_job':
        TunableSituationJobAndRoleState(
            description=
            '\n            The default job and role for a Sim in this situation. They only\n            have one role, so this is what will be given for them to do.\n            '
        )
    }
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    def __init__(self, *arg, **kwargs):
        super().__init__(*arg, **kwargs)
        self._duet_sim = None

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.karaoke_singer_job.job, cls.karaoke_singer_job.role_state)
                ]

    def _on_set_sim_job(self, sim, job_type):
        super()._on_set_sim_job(sim, job_type)
        self._duet_sim = sim

    @classmethod
    def default_job(cls):
        return cls.karaoke_singer_job.job

    def start_situation(self):
        super().start_situation()
        self._change_state(KaraokeDuetState())

    def sim_of_interest(self, sim_info):
        if self._duet_sim is not None and self._duet_sim.sim_info is sim_info:
            return True
        return False

    @classmethod
    def _states(cls):
        return (SituationStateData(1, KaraokeDuetState), )
class VetCustomerVendingMachineSituation(BusinessSituationMixin, SituationComplexCommon):
    INSTANCE_TUNABLES = {'customer_job_and_role_states': TunableSituationJobAndRoleState(description='\n            The job assigned to pet owners and the initial role when the situation starts.\n            ', tuning_group=GroupNames.ROLES), 'situation_state': VetCustomerState.TunableFactory(description='\n            A situation state that looks for them to run an interaction to\n            purchase an item from the vending machine so that the situation\n            can end.\n            ', locked_args={'time_out': None, 'allow_join_situation': True})}
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    @classmethod
    def _states(cls):
        return (SituationStateData(1, VetCustomerState, factory=cls.situation_state),)

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.customer_job_and_role_states.job, cls.customer_job_and_role_states.role_state)]

    @classmethod
    def default_job(cls):
        pass

    @property
    def customer_has_been_seen(self):
        return True

    def start_situation(self):
        super().start_situation()
        self._change_state(self.situation_state())
Esempio n. 24
0
class OrganizationMemberSingleJobSituation(OrganizationEventBase):
    INSTANCE_TUNABLES = {
        'job_and_role_state':
        TunableSituationJobAndRoleState(
            description=
            '\n            The job and role that a member will be used to fill in.\n            ',
            tuning_group=GroupNames.SITUATION)
    }

    @classmethod
    def _states(cls):
        return (SituationStateData(1, SituationState), )

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.job_and_role_state.job, cls.job_and_role_state.role_state)
                ]

    @classmethod
    def get_predefined_guest_list(cls):
        guest_list = SituationGuestList(invite_only=True)
        members_sim_ids = cls.get_members_sim_infos()
        for member_sim_id in members_sim_ids:
            guest_list.add_guest_info(
                SituationGuestInfo(member_sim_id, cls.job_and_role_state.job,
                                   RequestSpawningOption.DONT_CARE,
                                   BouncerRequestPriority.BACKGROUND_HIGH))
        return guest_list

    @classmethod
    def default_job(cls):
        return cls.job_and_role_state.job

    def start_situation(self):
        super().start_situation()
        self._change_state(SituationState())
class CafeGenericCustomerSituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {'pre_order_coffee_state': _PreOrderCoffeeState.TunableFactory(description='\n            The situation state used for when a Sim is arriving as a Cafe\n            Generic Sim.\n            ', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP, display_name='01_pre_order_coffee_situation_state'), 'order_coffee_state': _OrderCoffeeState.TunableFactory(description='\n            The situation state used for when a Sim is ordering coffee as a Cafe\n            Generic Sim.\n            ', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP, display_name='02_order_coffee_situation_state'), 'cafe_generic_state': _CafeGenericBehaviorState.TunableFactory(description='\n            The main state of the situation. This is where Sims will do \n            behavior after ordering coffee\n            ', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP, display_name='03_generic_behavior_state'), 'cafe_generic_job': TunableSituationJobAndRoleState(description="\n            The default job and role state for a Sim in this situation. This\n            shouldn't actually matter because the Situation will put the Sim in\n            the Order Coffee State when they are added.\n            ")}
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._cafe_sim = None

    @classmethod
    def _states(cls):
        return (SituationStateData(1, _PreOrderCoffeeState, factory=cls.pre_order_coffee_state), SituationStateData(2, _OrderCoffeeState, factory=cls.order_coffee_state), SituationStateData(3, _CafeGenericBehaviorState, factory=cls.cafe_generic_state))

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.cafe_generic_job.job, cls.cafe_generic_job.role_state)]

    def get_order_coffee_state(self):
        return self.order_coffee_state()

    def get_post_coffee_state(self):
        return self.cafe_generic_state()

    @classmethod
    def default_job(cls):
        return cls.cafe_generic_job.job

    def _on_set_sim_job(self, sim, job_type):
        super()._on_set_sim_job(sim, job_type)
        self._cafe_sim = sim

    def start_situation(self):
        super().start_situation()
        self._change_state(self.pre_order_coffee_state())

    def sim_of_interest(self, sim_info):
        if self._cafe_sim is not None and self._cafe_sim.sim_info is sim_info:
            return True
        return False
Esempio n. 26
0
class SituationComplexAdoptionPet(SituationComplexAdoption):
    INSTANCE_TUNABLES = {
        'adoption_officer_job_and_role':
        TunableSituationJobAndRoleState(
            description=
            '\n            The job and role state for the pet adoption officer.\n            '
        ),
        'pet_adoption_candidate_job_and_role':
        TunableSituationJobAndRoleState(
            description=
            '\n            The job and role state for the pets that are adoption candidates.\n            '
        ),
        'has_front_door_arrival_state':
        _HasFrontDoorArrivalState.TunableFactory(
            description=
            '\n            The arrival state for the adoption officer if the lot has a front\n            door.\n            ',
            display_name='1. Has Front Door Arrival State',
            tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP),
        'has_no_front_door_arrival_state':
        _HasNoFrontDoorArrivalState.TunableFactory(
            description=
            '\n            The arrival state for the adoption officer if the lot does not have\n            a front door.\n            ',
            display_name='1. Has No Front Door Arrival State',
            tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP),
        'spawn_pets_state':
        _SpawnPetsState.TunableFactory(
            description=
            '\n            The state in which adoption candidate pets are spawned.\n            ',
            display_name='2. Spawn Pets State',
            tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP),
        'interact_with_pets_state':
        _InteractWithPetsState.TunableFactory(
            description=
            '\n            The state for Sims to interact with adoption candidate pets.\n            ',
            display_name='3. Interact With Pets State',
            tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP),
        'wait_for_pets_to_despawn_state':
        _WaitForPetsToDespawnState.TunableFactory(
            description=
            '\n            The state where any adoption candidate pets that were not adopted\n            are despawned.\n            ',
            display_name='4. Wait For Pets To Despawn State',
            tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP),
        'pick_up_adoption_crate_state':
        _PickUpAdoptionCrateState.TunableFactory(
            description=
            '\n            The state for the adoption officer to pick up the adoption crate.\n            ',
            display_name='5. Pick Up Adoption Crate State',
            tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP),
        'leave_state':
        _LeaveState.TunableFactory(
            description=
            '\n            The state for the adoption officer to leave.\n            ',
            display_name='6. Leave State',
            tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP),
        'pet_crate_tag':
        TunableEnumWithFilter(
            description=
            '\n            Tag used to find the pet crate object.\n            ',
            tunable_type=Tag,
            default=Tag.INVALID,
            invalid_enums=(Tag.INVALID, ),
            filter_prefixes=('func', )),
        'pet_crate_object_definition':
        TunableReference(
            description=
            '\n            Object definition of the pet crate object that will be created as\n            part of this situation.\n            ',
            manager=services.definition_manager())
    }

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._pet_crate_object_id = None
        reader = self._seed.custom_init_params_reader
        if reader is None:
            self._pet_crate_x = None
            self._pet_crate_y = None
            self._pet_crate_z = None
        else:
            self._pet_crate_x = reader.read_float(PET_CRATE_X, None)
            self._pet_crate_y = reader.read_float(PET_CRATE_Y, None)
            self._pet_crate_z = reader.read_float(PET_CRATE_Z, None)
        self._register_test_event(TestEvent.OnExitBuildBuy)
        self._register_test_event(TestEvent.ObjectDestroyed)

    def handle_event(self, sim_info, event, resolver):
        if event == TestEvent.OnExitBuildBuy:
            if self.pet_crate is None:
                self._restore_crate()
            self._pet_crate_x = None
            self._pet_crate_y = None
            self._pet_crate_z = None
        if event == TestEvent.ObjectDestroyed:
            if services.current_zone().is_in_build_buy:
                destroyed_obj = resolver.get_resolved_arg('obj')
                if destroyed_obj is not None:
                    if destroyed_obj is self.pet_crate:
                        position = destroyed_obj.position
                        self._pet_crate_x = position.x
                        self._pet_crate_y = position.y
                        self._pet_crate_z = position.z

    def remove_destruction_listener(self):
        self._unregister_test_event(TestEvent.ObjectDestroyed)

    @classmethod
    def _states(cls):
        return (SituationStateData(1,
                                   _HasFrontDoorArrivalState,
                                   factory=cls.has_front_door_arrival_state),
                SituationStateData(
                    2,
                    _HasNoFrontDoorArrivalState,
                    factory=cls.has_no_front_door_arrival_state),
                SituationStateData(3,
                                   _SpawnPetsState,
                                   factory=cls.spawn_pets_state),
                SituationStateData(4,
                                   _InteractWithPetsState,
                                   factory=cls.interact_with_pets_state),
                SituationStateData(5,
                                   _WaitForPetsToDespawnState,
                                   factory=cls.wait_for_pets_to_despawn_state),
                SituationStateData(6,
                                   _PickUpAdoptionCrateState,
                                   factory=cls.pick_up_adoption_crate_state),
                SituationStateData(7, _LeaveState, factory=cls.leave_state))

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.adoption_officer_job_and_role.job,
                 cls.adoption_officer_job_and_role.role_state),
                (cls.pet_adoption_candidate_job_and_role.job,
                 cls.pet_adoption_candidate_job_and_role.role_state)]

    @classmethod
    def default_job(cls):
        pass

    @property
    def pet_crate(self):
        object_manager = services.object_manager()
        pet_crate = None
        if self._pet_crate_object_id is not None:
            pet_crate = object_manager.get(self._pet_crate_object_id)
        if pet_crate is None:
            for obj in services.object_manager().get_objects_with_tag_gen(
                    self.pet_crate_tag):
                pet_crate = obj
                self._pet_crate_object_id = pet_crate.id
                break
        return pet_crate

    def _on_set_sim_job(self, sim, job):
        super()._on_set_sim_job(sim, job)
        self._cur_state.on_set_sim_job(sim, job)

    def _on_remove_sim_from_situation(self, sim):
        super()._on_remove_sim_from_situation(sim)
        if self._cur_state is not None:
            self._cur_state.on_remove_sim_from_situation(sim)

    def adoption_officer_sim(self):
        sim = next(
            self.all_sims_in_job_gen(self.adoption_officer_job_and_role.job),
            None)
        return sim

    def adoptee_pets_gen(self):
        yield from self.all_sims_in_job_gen(
            self.pet_adoption_candidate_job_and_role.job)

    def start_situation(self):
        super().start_situation()
        if services.get_door_service().has_front_door():
            self._change_state(self.has_front_door_arrival_state())
        else:
            self._change_state(self.has_no_front_door_arrival_state())

    def _save_custom_situation(self, writer):
        super()._save_custom_situation(writer)
        pet_crate = self.pet_crate
        if pet_crate is not None:
            position = pet_crate.position
            writer.write_float(PET_CRATE_X, position.x)
            writer.write_float(PET_CRATE_Y, position.y)
            writer.write_float(PET_CRATE_Z, position.z)

    def load_situation(self):
        result = super().load_situation()
        if result:
            self._restore_crate()
            self._pet_crate_x = None
            self._pet_crate_y = None
            self._pet_crate_z = None
        return result

    def _restore_crate(self):
        if self._pet_crate_x is None:
            return
        obj = create_object(self.pet_crate_object_definition)
        if obj is None:
            return
        position = sims4.math.Vector3(float(self._pet_crate_x),
                                      float(self._pet_crate_y),
                                      float(self._pet_crate_z))
        starting_location = placement.create_starting_location(
            position=position)
        fgl_context = placement.create_fgl_context_for_object(
            starting_location, obj, ignored_object_ids=(obj.id, ))
        (position, orientation) = placement.find_good_location(fgl_context)
        if position is not None and orientation is not None:
            obj.move_to(translation=position, orientation=orientation)
        else:
            obj.destroy()
Esempio n. 27
0
class VetClinicDiagnosisSituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {
        'vet_job':
        TunableSituationJobAndRoleState(
            description=
            '\n            The job and role which the vet Sim is placed into.\n            ',
            tuning_group=GroupNames.ROLES),
        'pet_job':
        TunableSituationJobAndRoleState(
            description=
            '\n            The job and role which the pet Sim is placed into.\n            ',
            tuning_group=GroupNames.ROLES),
        'undiscovered_sickness_text':
        TunableLocalizedStringFactory(
            description=
            '\n            Text to use if a sickness is undiscovered.\n            ',
            tuning_group=GroupNames.UI),
        'undiscovered_symptom_text':
        TunableLocalizedStringFactory(
            description=
            '\n            Text to use if a symptom is undiscovered.\n            ',
            tuning_group=GroupNames.UI),
        '_progress_meter_settings':
        StatBasedSituationMeterData.TunableFactory(
            description=
            '\n            The meter used to track the progress of the diagnosis.\n            ',
            tuning_group=GroupNames.SITUATION,
            locked_args={'_meter_id': DIAGNOSIS_PROGRESS_METER_ID}),
        '_stress_meter_settings':
        StatBasedSituationMeterData.TunableFactory(
            description=
            '\n            The meter used to track the stress level of the patient.\n            ',
            tuning_group=GroupNames.SITUATION,
            locked_args={'_meter_id': PATIENT_STRESS_METER_ID}),
        'audio_sting_on_symptom_discovery':
        TunableResourceKey(
            description=
            '\n            The sound to play when a symptom is discovered.\n            ',
            resource_types=(sims4.resources.Types.PROPX, ),
            default=None,
            allow_none=True,
            tuning_group=GroupNames.AUDIO)
    }
    REMOVE_INSTANCE_TUNABLES = (
        '_buff', 'targeted_situation', '_resident_job',
        '_relationship_between_job_members', 'force_invite_only',
        'screen_slam_gold', 'screen_slam_silver', 'screen_slam_bronze',
        'screen_slam_no_medal', 'main_goal', '_main_goal_visibility_test',
        'minor_goal_chains', '_hidden_scoring_override',
        '_implies_greeted_status', '_level_data', 'weight_multipliers',
        'recommended_job_object_notification', 'recommended_job_object_text'
    ) + Situation.SITUATION_START_FROM_UI_REMOVE_INSTANCE_TUNABLES

    @classmethod
    def _states(cls):
        return (SituationStateData(1, WaitForDiagnosisActorsState),
                SituationStateData(2, DiagnosisSituationState))

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.vet_job.job, cls.vet_job.role_state),
                (cls.pet_job.job, cls.pet_job.role_state)]

    @classmethod
    def default_job(cls):
        return cls.vet_job.job

    @classmethod
    def get_tuned_jobs(cls):
        return [cls.vet_job.job, cls.pet_job.job]

    @classproperty
    def situation_serialization_option(cls):
        return SituationSerializationOption.DONT

    def __init__(self, *arg, **kwargs):
        super().__init__(*arg, **kwargs)
        self._started_from_load = services.current_zone(
        ) is None or not services.current_zone().is_zone_running

    @property
    def situation_display_type(self):
        return SituationDisplayType.VET

    @property
    def situation_display_priority(self):
        return SituationDisplayPriority.VET

    def get_pet(self):
        if self._started_from_load:
            return self._get_sim_from_guest_list(self.pet_job.job)
        return next(iter(self.all_sims_in_job_gen(self.pet_job.job)), None)

    def get_vet(self):
        if self._started_from_load:
            return self._get_sim_from_guest_list(self.vet_job.job)
        return next(iter(self.all_sims_in_job_gen(self.vet_job.job)), None)

    def start_situation(self):
        super().start_situation()
        self._register_test_event(TestEvent.BusinessClosed)
        self._change_state(WaitForDiagnosisActorsState())

    def handle_event(self, sim_info, event, resolver):
        if event == TestEvent.BusinessClosed:
            self._self_destruct()

    def get_create_op(self, *args, **kwargs):
        return distributor.ops.SituationStartOp(
            self, self.build_situation_start_message(), immediate=True)

    def on_added_to_distributor(self):
        super().on_added_to_distributor()
        if self._started_from_load and None not in (self.get_pet(),
                                                    self.get_vet()):
            self._change_state(DiagnosisSituationState())

    def build_situation_start_message(self):
        msg = super().build_situation_start_message()
        with ProtocolBufferRollback(msg.meter_data) as meter_data_msg:
            self._progress_meter_settings.build_data_message(meter_data_msg)
        with ProtocolBufferRollback(msg.meter_data) as meter_data_msg:
            self._stress_meter_settings.build_data_message(meter_data_msg)
        return msg

    def has_offered_goals(self):
        return False

    def refresh_situation_goals(self, resolver=None):
        self._send_goal_update_to_client(resolver=resolver)

    def send_icon_update_to_client(self):
        msg = Situations_pb2.SituationIconUpdate()
        msg.situation_id = self.id
        build_icon_info_msg(self.get_pet().get_icon_info_data(), None,
                            msg.icon_info)
        msg.icon_info.control_id = ICON_CONTROL_ID
        op = distributor.ops.SituationIconUpdateOp(msg)
        Distributor.instance().add_op(self, op)

    def _send_goal_update_to_client(self, resolver=None, completed_goal=None):
        pet = self.get_pet()
        if pet is None:
            return
        sickness = pet.sim_info.current_sickness
        op = distributor.ops.SituationGoalUpdateOp(
            self._create_situation_goal_update_msg(pet, sickness, resolver))
        Distributor.instance().add_op(self, op)

    def _create_situation_goal_update_msg(self, pet, sickness, resolver):
        msg = Situations_pb2.SituationGoalsUpdate()
        msg.goal_status = UiSituationGoalStatus.COMPLETED
        msg.situation_id = self.id
        self._set_major_goal_data(pet, sickness, msg.major_goal)
        self._set_minor_goals_data(pet, msg.goals)
        self._handle_completed_goal(resolver, sickness, msg)
        return msg

    def _handle_completed_goal(self, resolver, sickness, msg):
        recently_discovered_sickness = None if resolver is None else resolver.get_resolved_arg(
            'discovered_sickness')
        if recently_discovered_sickness is sickness:
            msg.completed_goal_id = SICKNESS_MAJOR_GOAL_ID
            return msg
        else:
            recently_discovered_symptom = None if resolver is None else resolver.get_resolved_arg(
                'discovered_symptom')
            if recently_discovered_symptom is not None:
                msg.completed_goal_id = SICKNESS_MINOR_GOAL_IDS[
                    sickness.get_ordered_symptoms().index(
                        recently_discovered_symptom)]
                return msg
        return msg

    def _set_major_goal_data(self, pet, sickness, major_goal_msg):
        is_sickness_discovered = False if sickness is None else pet.sim_info.sickness_tracker.has_discovered_sickness
        major_goal_name = sickness.display_name(
        ) if is_sickness_discovered else self.undiscovered_sickness_text()
        major_goal_msg.goal_id = SICKNESS_MAJOR_GOAL_ID
        major_goal_msg.goal_name = major_goal_name
        major_goal_msg.max_iterations = 1
        major_goal_msg.current_iterations = 1 if is_sickness_discovered else 0
        if self.main_goal_audio_sting is not None:
            major_goal_msg.audio_sting.type = self.main_goal_audio_sting.type
            major_goal_msg.audio_sting.group = self.main_goal_audio_sting.group
            major_goal_msg.audio_sting.instance = self.main_goal_audio_sting.instance

    def _set_minor_goals_data(self, pet, goals_msg):
        discovered_symptoms = pet.sim_info.sickness_tracker.discovered_symptoms
        while True:
            for i in range(0 if pet.sim_info.current_sickness is None else len(
                    pet.sim_info.current_sickness.symptoms)):
                is_symptom_discovered = len(
                    discovered_symptoms
                ) > i and pet.sim_info.was_symptom_discovered(
                    discovered_symptoms[i])
                symptom_goal_name = discovered_symptoms[i].display_name(
                ) if is_symptom_discovered else self.undiscovered_symptom_text(
                )
                with ProtocolBufferRollback(goals_msg) as goal_msg:
                    goal_msg.goal_id = SICKNESS_MINOR_GOAL_IDS[i]
                    goal_msg.goal_name = symptom_goal_name
                    goal_msg.max_iterations = 1
                    goal_msg.current_iterations = 1 if is_symptom_discovered else 0
                    if self.audio_sting_on_symptom_discovery is not None:
                        goal_msg.audio_sting.type = self.audio_sting_on_symptom_discovery.type
                        goal_msg.audio_sting.group = self.audio_sting_on_symptom_discovery.group
                        goal_msg.audio_sting.instance = self.audio_sting_on_symptom_discovery.instance
Esempio n. 28
0
class DjAudienceSituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {'dj_audience_state': _DjAudienceState.TunableFactory(description='\n            The main state for a dj audience Sim.\n            ', tuning_group=SituationComplexCommon.SITUATION_STATE_GROUP, display_name='01_dj_audience_state'), 'dj_audience_job_and_role': TunableSituationJobAndRoleState(description='\n            The job and role state for the dj audience members.\n            ')}
    REMOVE_INSTANCE_TUNABLES = Situation.NON_USER_FACING_REMOVE_INSTANCE_TUNABLES

    @classmethod
    def _states(cls):
        return (SituationStateData(1, _DjAudienceState, factory=cls.dj_audience_state),)

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.dj_audience_job_and_role.job, cls.dj_audience_job_and_role.role_state)]

    @classmethod
    def default_job(cls):
        return cls.dj_audience_job_and_role.situation_job

    def start_situation(self):
        super().start_situation()
        self._change_state(self.dj_audience_state())
class NeighborHangoutSituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {
        'player_sim_job_and_default_role_state':
        TunableSituationJobAndRoleState(
            description=
            '\n            The Situation Job and role stateto put player Sims in. \n            '
        ),
        'neighbor_job_and_default_role_state':
        TunableSituationJobAndRoleState(
            description=
            '\n            The Situation Job and Role State for the neighbor.\n            '
        ),
        '_ring_doorbell_state':
        _RingDoorbellState.TunableFactory(
            description=
            "\n            The state for the neighbor to ring the player's doorbell.\n            ",
            tuning_group=GroupNames.STATE),
        '_wait_to_be_greeted_state':
        _NeighborWaitToBeGreetedState.TunableFactory(
            description=
            '\n            The state for the neighbor to wait until the player invites them in\n            or they timeout.\n            ',
            tuning_group=GroupNames.STATE),
        '_hangout_state':
        _NeighborHangoutState.TunableFactory(
            description=
            '\n            The state for the neighbor to come in and hang out with the player.\n            ',
            tuning_group=GroupNames.STATE),
        'scheduling_tests':
        TunableTestSet(
            description=
            "\n            Tunable tests that run before scheduling this situation. If they\n            pass, the situation is weighed and considered for scheduling.\n            Otherwise it does not take up a slot in the situation manager\n            because the zone director won't consider it.\n            Participants: Actor = active sim, TargetSim = Sim from Job filter.\n            Tests fail if TargetSim is None.\n            "
        )
    }

    @classmethod
    def _states(cls):
        return (SituationStateData(1,
                                   _RingDoorbellState,
                                   factory=cls._ring_doorbell_state),
                SituationStateData(2,
                                   _NeighborWaitToBeGreetedState,
                                   factory=cls._wait_to_be_greeted_state),
                SituationStateData(3,
                                   _NeighborHangoutState,
                                   factory=cls._hangout_state))

    @classmethod
    def default_job(cls):
        pass

    @classmethod
    def situation_meets_starting_requirements(cls, **kwargs):
        owning_household = services.owning_household_of_active_lot()
        if owning_household is None or not owning_household.get_sims_at_home():
            return False
        neighbor_results = cls.get_filter_results_for_job()
        if not neighbor_results:
            return False
        else:
            for neighbor_result in neighbor_results:
                resolver = DoubleSimResolver(services.active_sim_info(),
                                             neighbor_result.sim_info)
                if cls.scheduling_tests.run_tests(resolver):
                    break
            else:
                return False
        return True

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.neighbor_job_and_default_role_state.job,
                 cls.neighbor_job_and_default_role_state.role_state),
                (cls.player_sim_job_and_default_role_state.job,
                 cls.player_sim_job_and_default_role_state.role_state)]

    @classmethod
    def get_filter_results_for_job(cls):
        active_sim_info = services.active_sim_info()
        neighbor_results = services.sim_filter_service().submit_filter(
            cls.neighbor_job_and_default_role_state.job.filter,
            callback=None,
            requesting_sim_info=active_sim_info,
            allow_yielding=False,
            blacklist_sim_ids={
                sim_info.sim_id
                for sim_info in services.active_household()
            },
            gsi_source_fn=cls.get_sim_filter_gsi_name)
        return neighbor_results

    @classmethod
    def get_predefined_guest_list(cls):
        active_sim_info = services.active_sim_info()
        neighbor_results = cls.get_filter_results_for_job()
        if not neighbor_results:
            return
        neighbor = random.choice(neighbor_results)
        guest_list = SituationGuestList(
            invite_only=True,
            host_sim_id=neighbor.sim_info.sim_id,
            filter_requesting_sim_id=active_sim_info.sim_id)
        guest_list.add_guest_info(
            SituationGuestInfo(neighbor.sim_info.sim_id,
                               cls.neighbor_job_and_default_role_state.job,
                               RequestSpawningOption.DONT_CARE,
                               BouncerRequestPriority.EVENT_VIP,
                               expectation_preference=True))
        return guest_list

    def start_situation(self):
        super().start_situation()
        self._change_state(self._ring_doorbell_state())

    def _issue_requests(self):
        super()._issue_requests()
        request = SelectableSimRequestFactory(
            self,
            callback_data=_RequestUserData(),
            job_type=self.player_sim_job_and_default_role_state.job,
            exclusivity=self.exclusivity)
        self.manager.bouncer.submit_request(request)
class ObstacleCourseSituation(SituationComplexCommon):
    INSTANCE_TUNABLES = {
        'coach_job_and_role_state':
        TunableSituationJobAndRoleState(
            description=
            '\n            Job and Role State for the coach Sim. Pre-populated as\n            the actor of the Situation.\n            ',
            tuning_group=GroupNames.ROLES),
        'athlete_job_and_role_state':
        TunableSituationJobAndRoleState(
            description=
            '\n            Job and Role State for the athlete. Pre-populated as the\n            target of the Situation.\n            ',
            tuning_group=GroupNames.ROLES),
        'run_course_state':
        RunCourseState.TunableFactory(tuning_group=GroupNames.STATE),
        'obstacle_tags':
        TunableTags(
            description=
            '\n            Tags to use when searching for obstacle course objects.\n            ',
            filter_prefixes=('Func_PetObstacleCourse', ),
            minlength=1),
        'setup_obstacle_state_value':
        ObjectStateValue.TunableReference(
            description=
            '\n            The state to setup obstacles before we run the course.\n            '
        ),
        'teardown_obstacle_state_value':
        ObjectStateValue.TunableReference(
            description=
            '\n            The state to teardown obstacles after we run the course or when the\n            situation ends.\n            '
        ),
        'failure_commodity':
        Commodity.TunableReference(
            description=
            '\n            The commodity we use to track how many times the athlete has failed\n            to overcome an obstacle.\n            '
        ),
        'obstacles_required':
        TunableRange(
            description=
            '\n            The number of obstacles required for the situation to be available. \n            If the obstacles that the pet can route to drops below this number,\n            the situation is destroyed.\n            ',
            tunable_type=int,
            default=4,
            minimum=1),
        'unfinished_notification':
        UiDialogNotification.TunableFactory(
            description=
            '\n            The dialog for when the situation ends prematurely or the dog never\n            finishes the course.\n            Token 0: Athlete\n            Token 1: Coach\n            Token 2: Time\n            ',
            tuning_group=GroupNames.UI),
        'finish_notifications':
        TunableList(
            description=
            '\n            A list of thresholds and notifications to play given the outcome of\n            the course. We run through the thresholds until one passes, and\n            play the corresponding notification.\n            ',
            tuning_group=GroupNames.UI,
            tunable=TunableTuple(
                description=
                '\n                A threshold and notification to play if the threshold passes.\n                ',
                threshold=TunableThreshold(
                    description=
                    '\n                    A threshold to compare the number of failures from the\n                    failure commodity when the course is finished.\n                    '
                ),
                notification=UiDialogNotification.TunableFactory(
                    description=
                    '\n                    Notification to play when the situation ends.\n                    Token 0: Athlete\n                    Token 1: Coach\n                    Token 2: Failure Count\n                    Token 3: Time\n                    '
                )))
    }

    @classmethod
    def _states(cls):
        return (SituationStateData(0, WaitForSimJobsState),
                SituationStateData(1,
                                   RunCourseState,
                                   factory=cls.run_course_state))

    @classmethod
    def _get_tuned_job_and_default_role_state_tuples(cls):
        return [(cls.coach_job_and_role_state.job,
                 cls.coach_job_and_role_state.role_state),
                (cls.athlete_job_and_role_state.job,
                 cls.athlete_job_and_role_state.role_state)]

    @classmethod
    def default_job(cls):
        pass

    @classmethod
    def get_prepopulated_job_for_sims(cls, sim, target_sim_id=None):
        prepopulate = [(sim.id, cls.coach_job_and_role_state.job.guid64)]
        if target_sim_id is not None:
            prepopulate.append(
                (target_sim_id, cls.athlete_job_and_role_state.job.guid64))
        return prepopulate

    @classmethod
    def get_obstacles(cls):
        object_manager = services.object_manager()
        found_objects = set()
        for tag in cls.obstacle_tags:
            found_objects.update(
                object_manager.get_objects_matching_tags({tag}))
        return found_objects

    @classmethod
    def is_situation_available(cls, *args, **kwargs):
        obstacles = cls.get_obstacles()
        if len(obstacles) < cls.obstacles_required:
            return TestResult(False, 'Not enough obstacles.')
        return super().is_situation_available(*args, **kwargs)

    @classproperty
    def situation_serialization_option(cls):
        return situations.situation_types.SituationSerializationOption.LOT

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        reader = self._seed.custom_init_params_reader
        if reader is not None:
            obstacles = self.get_obstacles()
            if not obstacles:
                self._self_destruct()
            self._obstacle_ids = {obstacle.id for obstacle in obstacles}
            self._course_start_time = DateAndTime(
                reader.read_uint64(OBSTACLE_COURSE_START_TIME_TOKEN,
                                   services.time_service().sim_now))
            self._course_end_time = DateAndTime(
                reader.read_uint64(OBSTACLE_COURSE_END_TIME_TOKEN,
                                   services.time_service().sim_now))
        else:
            self._obstacle_ids = set()
            self._course_start_time = None
            self._course_end_time = None
        self._course_progress = ObstacleCourseProgress.NOT_STARTED

    @property
    def course_progress(self):
        return self._course_progress

    @property
    def obstacle_ids(self):
        return self._obstacle_ids

    def _save_custom_situation(self, writer):
        super()._save_custom_situation(writer)
        if self._course_start_time is not None:
            writer.write_uint64(OBSTACLE_COURSE_START_TIME_TOKEN,
                                int(self._course_start_time))
        if self._course_end_time is not None:
            writer.write_uint64(OBSTACLE_COURSE_END_TIME_TOKEN,
                                int(self._course_end_time))

    def start_situation(self):
        super().start_situation()
        self._register_obstacle_course_events()
        self._change_state(WaitForSimJobsState())

    def _on_remove_sim_from_situation(self, sim):
        super()._on_remove_sim_from_situation(sim)
        self._self_destruct()

    def _on_add_sim_to_situation(self, sim, job_type, *args, **kwargs):
        super()._on_add_sim_to_situation(sim, job_type, *args, **kwargs)
        if self.get_coach() is not None and self.get_athlete() is not None:
            object_manager = services.object_manager()
            obstacles = {
                object_manager.get(obstacle_id)
                for obstacle_id in self._obstacle_ids
            }
            sim_info_manager = services.sim_info_manager()
            users = sim_info_manager.instanced_sims_gen()
            for user in users:
                if user in self._situation_sims:
                    continue
                for interaction in user.get_all_running_and_queued_interactions(
                ):
                    target = interaction.target
                    target = target.part_owner if target is not None and target.is_part else target
                    if target is not None and target in obstacles:
                        interaction.cancel(
                            FinishingType.SITUATIONS,
                            cancel_reason_msg='Obstacle Course Starting')
            self._change_state(self.run_course_state())

    def _register_obstacle_course_events(self):
        services.get_event_manager().register_single_event(
            self, TestEvent.ObjectDestroyed)
        services.get_event_manager().register_single_event(
            self, TestEvent.OnExitBuildBuy)

    def _unregister_obstacle_course_events(self):
        services.get_event_manager().unregister_single_event(
            self, TestEvent.ObjectDestroyed)
        services.get_event_manager().unregister_single_event(
            self, TestEvent.OnExitBuildBuy)

    def handle_event(self, sim_info, event, resolver):
        super().handle_event(sim_info, event, resolver)
        if event == TestEvent.ObjectDestroyed:
            destroyed_object = resolver.get_resolved_arg('obj')
            if destroyed_object.id in self._obstacle_ids:
                self._obstacle_ids.remove(destroyed_object.id)
                if len(self._obstacle_ids) < self.obstacles_required:
                    self._self_destruct()
        elif event == TestEvent.OnExitBuildBuy:
            self.validate_obstacle_course()

    def on_remove(self):
        coach = self.get_coach()
        athlete = self.get_athlete()
        if coach is not None and athlete is not None:
            if self.course_progress > ObstacleCourseProgress.NOT_STARTED and self.course_progress < ObstacleCourseProgress.FINISHED:
                course_end_time = services.time_service().sim_now
                course_time_span = course_end_time - self._course_start_time
                unfinished_dialog = self.unfinished_notification(coach)
                unfinished_dialog.show_dialog(
                    additional_tokens=(athlete, coach, course_time_span))
            athlete.commodity_tracker.remove_statistic(self.failure_commodity)
        self.teardown_obstacle_course()
        self._unregister_obstacle_course_events()
        super().on_remove()

    def start_course(self):
        self._course_progress = ObstacleCourseProgress.RUNNING
        self._course_start_time = services.time_service(
        ).sim_now if self._course_start_time is None else self._course_start_time

    def continue_course(self):
        self._change_state(self.run_course_state())

    def finish_course(self):
        self._course_end_time = services.time_service().sim_now
        self._course_progress = ObstacleCourseProgress.FINISHED
        self._change_state(self.run_course_state())

    def finish_situation(self):
        course_time_span = self._course_end_time - self._course_start_time
        athlete = self.get_athlete()
        coach = self.get_coach()
        failures = athlete.commodity_tracker.get_value(self.failure_commodity)
        for threshold_notification in self.finish_notifications:
            if threshold_notification.threshold.compare(failures):
                dialog = threshold_notification.notification(coach)
                dialog.show_dialog(additional_tokens=(athlete, coach, failures,
                                                      course_time_span))
                break
        else:
            logger.error(
                "Obstacle Course Situation doesn't have a threshold, notification for failure count of {}",
                failures)
        self._self_destruct()

    def setup_obstacle_course(self):
        obstacles = self.get_obstacles()
        if len(obstacles) < self.obstacles_required:
            self._self_destruct()
        self._obstacle_ids = {obstacle.id for obstacle in obstacles}

    def validate_obstacle_course(self):
        athlete = self.get_athlete()
        if athlete is None:
            self._self_destruct()
            return
        all_obstacles = self.get_obstacles()
        if len(all_obstacles) < self.obstacles_required:
            self._self_destruct()
            return
        valid_obstacles = set()
        for obstacle in all_obstacles:
            currentState = obstacle.get_state(
                self.setup_obstacle_state_value.state)
            if obstacle.is_connected(athlete):
                valid_obstacles.add(obstacle)
                if currentState == self.teardown_obstacle_state_value:
                    obstacle.set_state(self.setup_obstacle_state_value.state,
                                       self.setup_obstacle_state_value,
                                       immediate=True)
                    if currentState == self.setup_obstacle_state_value:
                        obstacle.set_state(
                            self.setup_obstacle_state_value.state,
                            self.teardown_obstacle_state_value,
                            immediate=True)
            elif currentState == self.setup_obstacle_state_value:
                obstacle.set_state(self.setup_obstacle_state_value.state,
                                   self.teardown_obstacle_state_value,
                                   immediate=True)
        if len(valid_obstacles) < self.obstacles_required:
            self._self_destruct()
        else:
            self._obstacle_ids = {obstacle.id for obstacle in valid_obstacles}

    def teardown_obstacle_course(self):
        obstacles = self.get_obstacles()
        for obstacle in obstacles:
            obstacle.set_state(self.teardown_obstacle_state_value.state,
                               self.teardown_obstacle_state_value,
                               immediate=True)

    def get_coach(self):
        return next(
            iter(self.all_sims_in_job_gen(self.coach_job_and_role_state.job)),
            None)

    def get_athlete(self):
        return next(
            iter(self.all_sims_in_job_gen(
                self.athlete_job_and_role_state.job)), None)