コード例 #1
0
ファイル: room.py プロジェクト: mjgorman/Lampost-Mud
 def _on_attach(self):
     self.denizens = []
     self.inven = []
     self.mobiles = defaultdict(set)
     self._garbage_pulse = ev.register_p(self.check_garbage, seconds=room_reset_time + 1)
     self.current_actions = ActionCache()
     self.current_actions.add(self.instance_providers)
     self.current_actions.add(self.features)
     self.current_actions.add(self.exits)
     self.reset()
     call_each(self.contents, 'attach')
コード例 #2
0
ファイル: entity.py プロジェクト: genzgd/Lampost-Mud
 def _on_attach(self):
     self._soul_objects = set()
     self.inven_actions = ActionCache()
     self.inven_actions.add(self.inven)
     self.followers = set()
     self.soul_actions = ActionCache()
コード例 #3
0
ファイル: room.py プロジェクト: mjgorman/Lampost-Mud
class Room(ChildDBO, Attachable, Scriptable):
    dbo_key_type = 'room'
    dbo_parent_type = 'area'

    @staticmethod
    def dbo_key_sort(key):
        return int(key.split(':')[1])

    desc = DBOCField()
    size = DBOCField(10)
    exits = DBOCField([], 'exit')
    extras = DBOCField([], 'base_item')
    mobile_resets = DBOCField([], 'mobile_reset')
    article_resets = DBOCField([], 'article_reset')
    features = DBOCField([], 'untyped')
    title = DBOCField()
    flags = DBOField({})
    instance_providers = AutoField([])

    instance = None

    _garbage_pulse = None

    def _on_attach(self):
        self.denizens = []
        self.inven = []
        self.mobiles = defaultdict(set)
        self._garbage_pulse = ev.register_p(self.check_garbage, seconds=room_reset_time + 1)
        self.current_actions = ActionCache()
        self.current_actions.add(self.instance_providers)
        self.current_actions.add(self.features)
        self.current_actions.add(self.exits)
        self.reset()
        call_each(self.contents, 'attach')

    def _on_detach(self):
        del self._garbage_pulse
        for mobile_list in self.mobiles.values():
            for mobile in mobile_list:
                if mobile.env != self:
                    mobile.change_env(self)
        call_each(self.contents, 'detach')

    @property
    def action_providers(self):
        return itertools.chain(self.features, self.exits, self.denizens, self.inven, self.instance_providers)

    @property
    def name(self):
        if self.instance:
            return "{} (instance {})".format(self.title, self.instance.instance_id)
        return self.title

    @property
    def contents(self):
        return itertools.chain(self.features, self.denizens, self.inven)

    @Shadow
    def long_desc(self):
        return self.desc

    @Shadow
    def glance(self, source, **_):
        return source.display_line(self.name, 'room')

    @Shadow
    def entity_enters(self, entity, enter_action, entry_msg=None):
        self.attach()
        self.receive_broadcast(entry_msg)
        entity.env = self
        self.denizens.append(entity)
        entity.pulse_stamp = ev.current_pulse
        self.current_actions.add(entity)
        call_each(self.contents, "entity_enter_env", entity, enter_action)

    def entity_leaves(self, entity, exit_action, exit_msg=None):
        self.receive_broadcast(exit_msg)
        self.denizens.remove(entity)
        self.current_actions.remove(entity)
        call_each(self.contents, "entity_leave_env", entity, exit_action)

    @Shadow
    def add_inven(self, article):
        self.inven.append(article)
        self.current_actions.add(article)
        article.pulse_stamp = ev.current_pulse

    def remove_inven(self, article):
        self.inven.remove(article)
        self.current_actions.remove(article)

    @Shadow
    def receive_broadcast(self, broadcast, **_):
        if not broadcast:
            return
        if getattr(broadcast, 'target', None) == self:
            broadcast.target = None
        call_each(self.contents, "receive_broadcast", broadcast)

    def broadcast(self, **kwargs):
        self.receive_broadcast(Broadcast(**kwargs))

    def first_look(self, source):
        self.examine(source)

    @Shadow
    def examine(self, source):
        source.display_line(self.name, 'room_title')
        source.display_line('HRT', 'room')
        source.display_line(self.long_desc(), 'room')
        source.display_line('HRB', 'room')
        if self.exits:
            for my_exit in self.exits:
                my_exit.examine(source)
        else:
            source.display_line("No obvious exits", 'exit')
        call_each([x for x in self.contents if x != source], 'glance', source)

    def short_exits(self):
        return ", ".join([ex.name for ex in self.exits])

    def find_exit(self, exit_dir):
        for my_exit in self.exits:
            if my_exit.direction == exit_dir:
                return my_exit

    @Shadow
    def allow_leave(self, source, leave_exit):
        pass

    def check_garbage(self):
        if hasattr(self, 'dirty'):
            if not self.instance:
                db.save_object(self)
            del self.dirty
        stale_pulse = ev.future_pulse(room_reset_time)
        for obj in self.contents:
            obj_pulse = getattr(obj, 'pulse_stamp', 0)
            if obj_pulse > stale_pulse or hasattr(obj, 'is_player'):
                return
        self.detach()

    @Shadow
    def reset(self):
        new_mobiles = defaultdict(list)
        for m_reset in self.mobile_resets:
            curr_count = len(self.mobiles[m_reset.mobile])
            for _ in range(m_reset.reset_count - curr_count):
                new_mobiles[m_reset.reset_key].append(m_reset.mobile.create_instance(self))
            if m_reset.reset_count <= curr_count < m_reset.reset_max:
                new_mobiles[m_reset.reset_key].append(m_reset.mobile.create_instance(self))

        for a_reset in self.article_resets:
            template = a_reset.article
            if a_reset.mobile_ref:
                for new_mobile in new_mobiles[a_reset.mobile_ref]:
                    quantity = random.randrange(a_reset.reset_count, a_reset.reset_max + 1)
                    if template.divisible:
                        article = template.create_instance(new_mobile)
                        article.quantity = quantity
                        new_mobile.add_inven(article)
                    else:
                        for _ in range(quantity):
                            article = template.create_instance(new_mobile)
                            new_mobile.add_inven(article)
                            if a_reset.load_type == 'equip':
                                new_mobile.equip_article(article)
            else:
                curr_count = len([entity for entity in self.inven if getattr(entity, 'template', None) == template])
                if template.divisible:
                    if not curr_count:
                        instance = template.create_instance(self)
                        instance.quantity = random.randrange(a_reset.reset_count, max(a_reset.reset_max, a_reset.reset_count) + 1)
                        instance.enter_env(self)
                else:
                    for _ in range(a_reset.reset_count - curr_count):
                        template.create_instance(self).enter_env(self)
                    if a_reset.reset_count <= curr_count < a_reset.reset_max:
                        template.create_instance(self).enter_env(self)

    def social(self):
        pass

    def _pre_reload(self):
        if self.attached:
            self.limbo_players = [denizen for denizen in self.denizens if hasattr(denizen, 'is_player')]
            for player in self.limbo_players:
                player.leave_env(self)
            self.detach()

    def _on_reload(self):
        if hasattr(self, 'limbo_players'):
            for player in self.limbo_players:
                player.enter_env(self)
            del self.limbo_players
コード例 #4
0
ファイル: entity.py プロジェクト: genzgd/Lampost-Mud
class Entity(DBOAspect, Attachable):
    inven = DBOField([], 'untyped')

    status = 'ok'
    living = True
    instance = None

    entry_msg = BroadcastMap(e='{n} materializes.', ea="{n} arrives from the {N}.")
    exit_msg = BroadcastMap(e='{n} dematerializes.', ea="{n} leaves to the {N}.")

    def _on_attach(self):
        self._soul_objects = set()
        self.inven_actions = ActionCache()
        self.inven_actions.add(self.inven)
        self.followers = set()
        self.soul_actions = ActionCache()

    def _on_detach(self):
        for follower in self.followers:
            del follower.following
            follower.display_line("You are no longer following {}.".format(self.name))
        for item in list(itertools.chain(self.inven, self._soul_objects)):
            if hasattr(item, 'detach'):
                item.detach()
            if hasattr(item, 'detach_shared'):
                item.detach_shared(self)
        self.unfollow()
        self.leave_env()
        del self.soul_actions
        del self.inven_actions
        del self._soul_objects

    def _on_reload(self):
        if self.attached:
            self.inven_actions.refresh(self.inven)
            self.soul_actions.refresh(self._soul_objects)

    @property
    def current_actions(self):
        return [self.env.current_actions, self.inven_actions, self.soul_actions, mud_actions]

    def enhance_soul(self, action):
        self._soul_objects.add(action)
        self.soul_actions.add(action)

    def diminish_soul(self, action):
        if action in self._soul_objects:
            self._soul_objects.remove(action)
            self.soul_actions.remove(action)

    def add_inven(self, article):
        self.inven.append(article)
        self.inven_actions.add(article)

    def remove_inven(self, article):
        try:
            self.inven.remove(article)
        except ValueError:
            pass
        self.inven_actions.remove(article)

    def entity_enter_env(self, *_):
        pass

    def entity_leave_env(self, *_):
        pass

    def parse(self, command):
        if command.startswith("'"):
            command = 'say ' + command[1:]
        elif command.startswith(':'):
            command = 'emote ' + command[1:]
        try:
            action, act_args = parse_actions(self, command)
            self.start_action(action, act_args)
        except ParseError as error:
            self.handle_parse_error(error, command)

    def filter_actions(self, matches):
        return matches

    @action_handler
    def start_action(self, action, act_args):
        if hasattr(action, 'prepare_action'):
            action.prepare_action(**act_args)
        self.process_action(action, act_args)
        self.check_follow(action, act_args)

    @action_handler
    def process_action(self, action, act_args):
        response = action(**act_args)
        if isinstance(response, str):
            self.display_line(response)
        elif response:
            self.output(response)

    def check_follow(self, action, act_args):
        if getattr(action, 'can_follow', False):
            for follower in self.followers:
                if has_action(follower, action, act_args['verb']):
                    follow_args = act_args.copy()
                    follow_args['source'] = follower
                    follower.start_action(action, follow_args)

    def handle_parse_error(self, error, command):
        self.display_line(error.client_message, 'system')

    def social(self, **_):
        pass

    def follow(self, leader):
        leader.followers.add(self)
        self.broadcast(s="You start following {N}.", t="{n} starts following you.", e="{n} starts following {N}.", target=leader)

    def unfollow(self):
        following = getattr(self, 'following', None)
        if following:
            self.display_line("You are no longer following {}".format(following.name))
            following.display_line("{} is no longer following you.".format(self.name))
            following.followers.remove(self)
            del self.following

    def examine(self, source):
        super().examine(source)
        source.display_line("{0} is carrying:".format(self.name))
        if self.inven:
            for article in self.inven:
                article.glance(source)
        else:
            source.display_line("Nothing")

    def change_env(self, new_env, exit_action=None):
        if new_env:
            self.leave_env(exit_action)
            self.enter_env(new_env, exit_action)
        else:
            log.error("Entity {} changed to null environment", self.name)

    def leave_env(self, exit_action=None):
        if self.env:
            old_env = self.env
            self.env = None
            exit_msg = Broadcast(getattr(exit_action, 'exit_msg', self.exit_msg), self, exit_action, silent=True)
            old_env.entity_leaves(self, exit_action, exit_msg)

    def enter_env(self, new_env, enter_action=None):
        entry_msg = Broadcast(getattr(enter_action, 'entry_msg', self.entry_msg), self, silent=True)
        entry_msg.target = getattr(enter_action, 'from_name', None)
        new_env.entity_enters(self, enter_action, entry_msg)
        new_instance = getattr(self.env, 'instance', None)
        if self.instance != new_instance:
            if self.instance:
                self.instance.remove_entity(self)
                del self.instance_id
            if new_instance:
                new_instance.add_entity(self)
                self.instance_id = new_instance.instance_id
        if self.instance:
            self.instance_room_id = self.env.dbo_id
        elif self.env.dbo_id:
            self.room_id = self.env.dbo_id
        self.env.first_look(self)

    def broadcast(self, **kwargs):
        broadcast = Broadcast(**kwargs)
        broadcast.source = self
        if self.env:
            self.env.receive_broadcast(broadcast)

    def display_line(self, line, display='default'):
        pass

    def output(self, response):
        pass

    def can_see(self, target):
        return True

    def check_inven(self, article, quantity=None):
        pass

    def check_drop(self, article, quantity=None):
        pass

    def die(self):
        self.exit_msg = BroadcastMap(s="{n} expires, permanently.")
        for article in reversed(self.inven):
            article.current_slot = None
            article.drop(self)

        self.leave_env()
        self.status = 'dead'
        self.detach()

    @property
    def display_status(self):
        return {'status': self.status}

    @property
    def dead(self):
        return self.status == 'dead'