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_attach(self): self._soul_objects = set() self.inven_actions = ActionCache() self.inven_actions.add(self.inven) self.followers = set() self.soul_actions = ActionCache()
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
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'