Example #1
0
def query_object_properties(typeclass_key, object_key):
    """
    Query all properties of the given object.

    Args:
        typeclass_key: (string) typeclass' key.
        object_key: (string) object' key.
    """
    # Get fields.
    fields = []
    fields.append({
        "name": "level",
        "label": _("Level"),
        "help_text": _("Properties's level.")
    })

    properties_info = TYPECLASS(typeclass_key).get_properties_info()
    for key, info in properties_info.items():
        if info["mutable"]:
            continue

        fields.append({
            "name": key,
            "label": info["name"],
            "help_text": info["desc"]
        })

    if len(fields) == 1:
        # No custom properties.
        table = {
            "fields": [],
            "records": [],
        }
        return table

    # Get rows.
    levels = []
    data = {}
    records = OBJECT_PROPERTIES.get_properties_all_levels(object_key)
    for record in records:
        if record.level not in levels:
            levels.append(record.level)
            data[record.level] = {"level": record.level}
        data[record.level][record.property] = record.value

    rows = []
    for level in levels:
        line = [data[level].get(field["name"], "") for field in fields]
        rows.append(line)

    table = {
        "fields": fields,
        "records": rows,
    }

    return table
Example #2
0
class MudderyCommonNPC(TYPECLASS("BASE_NPC")):
    """
    The character not controlled by players.
    """
    typeclass_key = "COMMON_NPC"
    typeclass_name = _("Common NPC", "typeclasses")
    model_name = "common_npcs"
Example #3
0
    def set_typeclass(self, typeclass_key):
        """
        Set object's typeclass.
        
        Args:
            typeclass_key: (string) Typeclass's key.
        """
        typeclass_cls = TYPECLASS(typeclass_key)
        if not typeclass_cls:
            logger.log_errmsg("Can not get %s's typeclass: %s." %
                              (self.get_data_key(), typeclass_key))
            return

        if type(self) == typeclass_cls:
            # No change.
            return

        if not hasattr(self, 'swap_typeclass'):
            logger.log_errmsg("%s cannot have a type at all!" %
                              self.get_data_key())
            return

        # Set new typeclass.
        # It will call target typeclass's at_object_creation hook.
        # You should prevent at_object_creation rewrite current attributes.
        self.swap_typeclass(typeclass_cls, clean_attributes=False)
        if typeclass_cls.path != self.typeclass_path:
            logger.log_errmsg("%s's typeclass %s is wrong!" %
                              (self.get_data_key(), typeclass_cls.path))
            return
Example #4
0
def query_typeclass_table(typeclass_key):
    """
    Query a table of objects of the same typeclass.

    Args:
        typeclass_key: (string) typeclass's key.
    """
    typeclass_cls = TYPECLASS(typeclass_key)
    if not typeclass_cls:
        raise MudderyError(ERR.no_table,
                           "Can not find typeclass %s" % typeclass_key)

    # get all tables' name
    tables = typeclass_cls.get_models()
    if not tables:
        raise MudderyError(ERR.no_table,
                           "Can not get tables of %s" % typeclass_key)

    # get all tables' fields
    # add the first table
    table_fields = query_fields(tables[0])
    fields = [field for field in table_fields if field["name"] != "id"]

    # add other tables
    for table in tables[1:]:
        table_fields = query_fields(table)
        fields.extend([
            field for field in table_fields
            if field["name"] != "id" and field["name"] != "key"
        ])

    # get all tables' data
    records = general_query_mapper.get_all_from_tables(tables)

    rows = []
    for record in records:
        line = [str(record[field["name"]]) for field in fields]
        rows.append(line)

    table = {
        "fields": fields,
        "records": rows,
    }
    return table
Example #5
0
def query_object_form(base_typeclass, obj_typeclass, obj_key):
    """
    Query all data of an object.

    Args:
        base_typeclass: (string) candidate typeclass group.
        obj_typeclass: (string, optional) object's typeclass. If it is empty, use the typeclass of the object
                        or use base typeclass as object's typeclass.
        obj_key: (string) object's key. If it is empty, query an empty form.
    """
    candidate_typeclasses = TYPECLASS_SET.get_group(base_typeclass)
    if not candidate_typeclasses:
        raise MudderyError(ERR.no_table,
                           "Can not find typeclass: %s" % base_typeclass)

    if not obj_typeclass:
        if obj_key:
            # Get typeclass from the object's record
            table_name = TYPECLASS("OBJECT").model_name
            record = general_query_mapper.get_record_by_key(
                table_name, obj_key)
            obj_typeclass = record.typeclass
        else:
            # Or use the base typeclass
            obj_typeclass = base_typeclass

    typeclass = TYPECLASS_SET.get(obj_typeclass)
    if not typeclass:
        raise MudderyError(ERR.no_table,
                           "Can not find typeclass: %s" % obj_typeclass)
    table_names = typeclass.get_models()

    forms = []
    for table_name in table_names:
        if obj_key:
            object_form = query_form(table_name, key=obj_key)
        else:
            object_form = query_form(table_name)

        forms.append({"table": table_name, "fields": object_form})

    # add typeclasses
    if len(forms) > 0:
        for field in forms[0]["fields"]:
            if field["name"] == "typeclass":
                # set typeclass to the new value
                field["value"] = obj_typeclass
                field["type"] = "Select"
                field["choices"] = [
                    (key, cls.typeclass_name + " (" + key + ")")
                    for key, cls in candidate_typeclasses.items()
                ]
                break

    return forms
Example #6
0
    def after_data_loaded(self):
        """
        Load goods data.

        Returns:
            None
        """
        self.available = False

        self.shop_key = getattr(self.system, "shop", "")
        self.goods_key = getattr(self.system, "goods", "")
        self.goods_level = getattr(self.system, "level", 0)

        # set goods information
        self.price = getattr(self.system, "price", 0)
        self.unit_key = getattr(self.system, "unit", "")
        self.number = getattr(self.system, "number", 0)
        self.condition = getattr(self.system, "condition", "")

        # get price unit information
        try:
            # Get record.
            obj_model_name = TYPECLASS("OBJECT").model_name
            unit_record = WorldData.get_table_data(obj_model_name,
                                                   key=self.unit_key)
            unit_record = unit_record[0]
        except Exception as e:
            logger.log_errmsg("Can not find %s's price unit %s." %
                              (self.goods_key, self.unit_key))
            return

        self.unit_name = unit_record.name

        # load goods
        try:
            obj_record = WorldData.get_table_data(obj_model_name,
                                                  key=self.goods_key)
            obj_record = obj_record[0]
            goods_models = TYPECLASS_SET.get_class_modeles(
                obj_record.typeclass)
            goods_data = WorldData.get_tables_data(goods_models,
                                                   key=self.goods_key)
        except Exception as e:
            logger.log_errmsg("Can not find goods %s." % self.goods_key)
            return

        self.name = goods_data["name"]
        self.desc = goods_data["desc"]
        self.icon = goods_data.get("icon", None)

        self.available = True
Example #7
0
    def calc_combat_rewards(self, winners, losers):
        """
        Called when the character wins the combat.

        Args:
            winners: (List) all combat winners.
            losers: (List) all combat losers.

        Returns:
            (dict) reward dict
        """
        rewards = {}
        for winner in winners:
            winner_char = self.characters[winner]["char"]
            exp = 0
            loots = []
            for loser in losers:
                loser_char = self.characters[loser]["char"]
                exp += loser_char.provide_exp(self)
                obj_list = loser_char.loot_handler.get_obj_list(winner_char)
                if obj_list:
                    loots.extend(obj_list)

            obj_list = []
            if loots:
                obj_model_name = TYPECLASS("OBJECT").model_name

                for obj_info in loots:
                    try:
                        obj_record = WorldData.get_table_data(obj_model_name, key=obj_info["object"])
                        obj_record = obj_record[0]
                        goods_models = TYPECLASS_SET.get_class_modeles(obj_record.typeclass)
                        goods_data = WorldData.get_tables_data(goods_models, key=obj_info["object"])

                        obj_list.append({
                            "object": obj_info["object"],
                            "number": obj_info["number"],
                            "name": goods_data["name"],
                            "icon": goods_data.get("icon", None),
                            "reject": "",
                        })
                    except Exception as e:
                        logger.log_errmsg("Can not loot object %s." % obj_info["object"])
                        pass

            rewards[winner] = {
                "exp": exp,
                "loots": obj_list,
            }

        return rewards
Example #8
0
class MudderySkillBook(TYPECLASS("COMMON_OBJECT")):
    """
    This is a skill book. Players can use it to learn a new skill.
    """
    typeclass_key = "SKILL_BOOK"
    typeclass_name = _("Skill Book", "typeclasses")
    model_name = "skill_books"

    def get_available_commands(self, caller):
        """
        This returns a list of available commands.
        "args" must be a string without ' and ", usually it is self.dbref.
        """
        commands = []
        if self.db.number > 0:
            commands.append({
                "name": _("Use"),
                "cmd": "use",
                "args": self.dbref
            })

        commands.extend(
            super(MudderySkillBook, self).get_available_commands(caller))

        return commands

    def take_effect(self, user, number):
        """
        Use this object.

        Args:
            user: (object) the object who uses this
            number: (int) the number of the object to use

        Returns:
            (result, number):
                result: (string) a description of the result
                number: (int) actually used number
        """
        if not user:
            raise ValueError("User should not be None.")

        skill_key = getattr(self.system, "skill", None)
        if not skill_key:
            return _("No effect."), 0

        if user.learn_skill(skill_key, False, False):
            return _("You learned skill."), 1
        else:
            return _("No effect."), 0
Example #9
0
class MudderyArea(TYPECLASS("OBJECT")):
    """
    Areas are compose the whole map. Rooms are belongs to areas.
    """
    typeclass_key = "AREA"
    typeclass_name = _("Area", "typeclasses")
    model_name = "world_areas"

    def at_object_creation(self):
        """
        Called once, when this object is first created. This is the
        normal hook to overload for most object types.
        """
        super(MudderyArea, self).at_object_creation()
        self.background = None

    def after_data_loaded(self):
        """
        Set data_info to the object.
        """
        super(MudderyArea, self).after_data_loaded()

        # get background
        self.background = None
        resource = getattr(self.system, "background", None)
        if resource:
            try:
                resource_info = ImageResource.get(resource)
                resource_info = resource_info[0]
                self.background = {
                    "resource": resource_info.resource,
                    "width": resource_info.image_width,
                    "height": resource_info.image_height
                }
            except Exception as e:
                logger.log_tracemsg("Load background %s error: %s" %
                                    (resource, e))

    def get_appearance(self, caller):
        """
        This is a convenient hook for a 'look'
        command to call.
        """
        info = super(MudderyArea, self).get_appearance(caller)

        # add background
        info["background"] = getattr(self, "background", None)

        return info
Example #10
0
    def attack_target(self, target, desc=""):
        """
        Attack a target.

        Args:
            target: (object) the target object.
            desc: (string) string to describe this attack

        Returns:
            (boolean) attack begins
        """
        if self.is_in_combat():
            # already in battle
            logger.log_errmsg("%s is already in battle." % self.dbref)
            return False

        # search target
        if not target:
            logger.log_errmsg("Can not find the target.")
            return False

        if not target.is_typeclass(TYPECLASS(
                settings.GENERAL_CHARACTER_TYPECLASS_KEY),
                                   exact=False):
            # Target is not a character.
            logger.log_errmsg("Can not attack the target %s." % target.dbref)
            return False

        if target.is_in_combat():
            # obj is already in battle
            logger.log_errmsg("%s is already in battle." % target.dbref)
            return False

        # create a new combat handler
        chandler = create_script(settings.NORMAL_COMBAT_HANDLER)

        # set combat team and desc
        chandler.set_combat(combat_type=CombatType.NORMAL,
                            teams={
                                1: [target],
                                2: [self]
                            },
                            desc=desc,
                            timeout=0)

        return True
Example #11
0
class MudderyObjectCreator(TYPECLASS("WORLD_OBJECT")):
    """
    This object loads attributes from world data on init automatically.
    """
    typeclass_key = "WORLD_OBJECT_CREATOR"
    typeclass_name = _("Object Creator", "typeclasses")
    model_name = "object_creators"

    # initialize loot handler in a lazy fashion
    @lazy_property
    def loot_handler(self):
        return LootHandler(self, CreatorLootList.get(self.get_data_key()))

    def after_data_loaded(self):
        """
        Set data_info to the object."
        """
        super(MudderyObjectCreator, self).after_data_loaded()

        # Load creator info.
        self.loot_verb = getattr(self.system, "loot_verb", None)
        if not self.loot_verb:
            self.loot_verb = _("Loot")
        self.loot_condition = getattr(self.system, "loot_condition", None)

    def get_available_commands(self, caller):
        """
        This returns a list of available commands.
        "args" must be a string without ' and ", usually it is self.dbref.
        """
        if not STATEMENT_HANDLER.match_condition(self.loot_condition, caller,
                                                 self):
            return []

        commands = [{
            "name": self.loot_verb,
            "cmd": "loot",
            "args": self.dbref
        }]
        return commands

    def loot(self, caller):
        """
        Loot objects.
        """
        self.loot_handler.loot(caller)
Example #12
0
class MudderyWorldNPC(TYPECLASS("BASE_NPC")):
    """
    The character not controlled by players.
    """
    typeclass_key = "WORLD_NPC"
    typeclass_name = _("World NPC", "typeclasses")
    model_name = "world_npcs"

    def after_data_loaded(self):
        """
        Init the character.
        """
        super(MudderyWorldNPC, self).after_data_loaded()

        # if it is dead, reborn at init.
        if not self.is_alive():
            if not self.is_temp and self.reborn_time > 0:
                self.reborn()
Example #13
0
def delete_object(obj_key, base_typeclass=None):
    """
    Delete an object from all tables under the base typeclass.
    """
    if not base_typeclass:
        table_name = TYPECLASS("OBJECT").model_name
        record = general_query_mapper.get_record_by_key(table_name, obj_key)
        base_typeclass = record.typeclass

    typeclasses = TYPECLASS_SET.get_group(base_typeclass)
    tables = set()
    for key, value in typeclasses.items():
        tables.update(value.get_models())

    with transaction.atomic():
        for table in tables:
            try:
                general_query_mapper.delete_record_by_key(table, obj_key)
            except ObjectDoesNotExist:
                pass
Example #14
0
    def match_condition(self, quest_key):
        """
        Check if the quest matches its condition.
        Args:
            quest_key: (string) quest's key

        Returns:
            (boolean) result
        """
        # Get quest's record.
        model_name = TYPECLASS("QUEST").model_name
        if not model_name:
            return False

        try:
            record = WorldData.get_table_data(model_name, key=quest_key)
            record = record[0]
            return STATEMENT_HANDLER.match_condition(record.condition, self.owner, None)
        except Exception as e:
            logger.log_errmsg("Can't get quest %s's condition: %s" % (quest_key, e))
        return False
Example #15
0
def get_object_record(obj_key):
    """
    Query the object's record.

    Args:
        obj_key: (string) The key of the object.

    Returns:
        The object's data record.
    """
    record = None
    model_name = TYPECLASS("OBJECT").model_name
    try:
        # Get record.
        record = WorldData.get_table_data(model_name, key=obj_key)
        record = record[0]
    except Exception as e:
        ostring = "Can not get record %s in %s: %s." % (obj_key, model_name, e)
        print(ostring)
        print(traceback.print_exc())

    return record
Example #16
0
    def load_data(self, level=None, reset_location=True):
        """
        Set data to the object.
        """
        key = self.get_data_key()
        if key:
            base_model = TYPECLASS("OBJECT").model_name

            # Get the object's base data
            self.load_base_data(base_model, key)

            # reset typeclass
            typeclass = getattr(self.system, "typeclass", "")
            if typeclass:
                self.set_typeclass(typeclass)
            else:
                logger.log_errmsg("%s does not have a typeclass." % key)

            # Load system data except base data.
            self.load_system_data(base_model, key)

            # Load custom properties.
            if level is None:
                if self.attributes.has("level"):
                    level = self.db.level
                else:
                    # Use default level.
                    level = getattr(self.system, "level", 0)
                    self.db.level = level

            self.load_custom_properties(level)

        self.after_data_loaded()

        if not self.location and reset_location:
            self.set_location(getattr(self.system, "location", ""))
Example #17
0
def update_object_key(typeclass_key, old_key, new_key):
    """
    Update an object's key in other tables.

    Args:
        typeclass: (string) object's typeclass.
        old_key: (string) object's old key.
        new_key: (string) object's new key
    """
    # The object's key has changed.
    typeclass = TYPECLASS(typeclass_key)
    if issubclass(typeclass, TYPECLASS("AREA")):
        # Update relative room's location.
        model_name = TYPECLASS("ROOM").model_name
        if model_name:
            general_query_mapper.filter_records(
                model_name, location=old_key).update(location=new_key)
    elif issubclass(typeclass, TYPECLASS("ROOM")):
        # Update relative exit's location.
        model_name = TYPECLASS("EXIT").model_name
        if model_name:
            general_query_mapper.filter_records(
                model_name, location=old_key).update(location=new_key)
            general_query_mapper.filter_records(
                model_name, destination=old_key).update(destination=new_key)

        # Update relative world object's location.
        model_name = TYPECLASS("WORLD_OBJECT").model_name
        if model_name:
            general_query_mapper.filter_records(
                model_name, location=old_key).update(location=new_key)

        # Update relative world NPC's location.
        model_name = TYPECLASS("WORLD_NPC").model_name
        if model_name:
            general_query_mapper.filter_records(
                model_name, location=old_key).update(location=new_key)
Example #18
0
class MudderyBaseNPC(TYPECLASS("CHARACTER")):
    """
    The character not controlled by players.
    """
    typeclass_key = "BASE_NPC"
    typeclass_name = _("Base None Player Character", "typeclasses")
    model_name = "base_npcs"

    def at_object_creation(self):
        """
        Called once, when this object is first created. This is the
        normal hook to overload for most object types.

        """
        super(MudderyBaseNPC, self).at_object_creation()

        # NPC's shop
        if not self.attributes.has("shops"):
            self.db.shops = {}

    def after_data_loaded(self):
        """
        Init the character.
        """
        super(MudderyBaseNPC, self).after_data_loaded()

        # Character can auto fight.
        self.auto_fight = True

        # set home
        self.home = self.location

        # load dialogues.
        self.load_dialogues()

        # load shops
        self.load_shops()

    def load_dialogues(self):
        """
        Load dialogues.
        """
        dialogues = NPCDialogues.get(self.get_data_key())

        self.default_dialogues = [
            dialogue.dialogue for dialogue in dialogues
            if dialogue.dialogue and dialogue.default
        ]
        self.dialogues = [
            dialogue.dialogue for dialogue in dialogues
            if dialogue.dialogue and not dialogue.default
        ]

    def load_shops(self):
        """
        Load character's shop.
        """
        # shops records
        shop_records = NPCShops.get(self.get_data_key())

        shop_keys = set([record.shop for record in shop_records])

        # remove old shops
        for shop_key in self.db.shops:
            if shop_key not in shop_keys:
                # remove this shop
                self.db.shops[shop_key].delete()
                del self.db.shops[shop_key]

        # add new shop
        for shop_record in shop_records:
            shop_key = shop_record.shop
            if shop_key not in self.db.shops:
                # Create shop object.
                shop_obj = build_object(shop_key)
                if not shop_obj:
                    logger.log_errmsg("Can't create shop: %s" % shop_key)
                    continue

                self.db.shops[shop_key] = shop_obj
                shop_obj.set_owner(self)

    def get_available_commands(self, caller):
        """
        This returns a list of available commands.
        """
        commands = []
        if self.is_alive():
            if self.dialogues or self.default_dialogues:
                # If the character have something to talk, add talk command.
                commands.append({
                    "name": _("Talk"),
                    "cmd": "talk",
                    "args": self.dbref
                })

            # Add shops.
            for shop_obj in self.db.shops.values():
                if not shop_obj.is_visible(caller):
                    continue

                verb = shop_obj.verb
                if not verb:
                    verb = shop_obj.get_name()
                commands.append({
                    "name": verb,
                    "cmd": "shopping",
                    "args": shop_obj.dbref
                })

            if self.friendly <= 0:
                commands.append({
                    "name": _("Attack"),
                    "cmd": "attack",
                    "args": self.dbref
                })

        return commands

    def have_quest(self, caller):
        """
        If the npc can complete or provide quests.
        Returns (can_provide_quest, can_complete_quest).
        """
        return DIALOGUE_HANDLER.have_quest(caller, self)

    def leave_combat(self):
        """
        Leave the current combat.
        """
        status = None
        opponents = None
        rewards = None
        if self.ndb.combat_handler:
            result = self.ndb.combat_handler.get_combat_result(self.id)
            if result:
                status, opponents, rewards = result

        if not self.db.is_combat_instance:
            if status == defines.COMBAT_LOSE:
                self.die(opponents)

            super(MudderyBaseNPC, self).leave_combat()

            if status != defines.COMBAT_LOSE:
                self.recover()
        else:
            super(MudderyBaseNPC, self).leave_combat()
Example #19
0
class MudderyLockedExit(TYPECLASS("EXIT")):
    """
    Characters must unlock these exits to pass it.
    The view and commands of locked exits are different from unlocked exits.
    """
    typeclass_key = "LOCKED_EXIT"
    typeclass_name = _("Locked Exit", "typeclasses")
    model_name = "exit_locks"

    def after_data_loaded(self):
        """
        Set data_info to the object."
        """
        super(MudderyLockedExit, self).after_data_loaded()

        self.unlock_condition = getattr(self.system, "unlock_condition", "")
        self.unlock_verb = getattr(self.system, "unlock_verb", "")
        self.locked_desc = getattr(self.system, "locked_desc", "")
        self.auto_unlock = getattr(self.system, "auto_unlock", False)
        self.unlock_forever = getattr(self.system, "unlock_forever", True)

    def at_before_traverse(self, traversing_object):
        """
        Called just before an object uses this object to traverse to
        another object (i.e. this object is a type of Exit)

        Args:
            traversing_object (Object): The object traversing us.

        Notes:
            The target destination should normally be available as
            `self.destination`.
            
            If this method returns False/None, the traverse is cancelled
            before it is even started.

        """
        if not super(MudderyLockedExit,
                     self).at_before_traverse(traversing_object):
            return False

        # Only can pass exits which have already been unlocked.
        if traversing_object.is_exit_unlocked(self.get_data_key()):
            if not self.unlock_forever:
                # lock the exit again
                traversing_object.lock_exit(self)
            return True

        if self.auto_unlock and self.can_unlock(traversing_object):
            # Can unlock the exit automatically.
            if self.unlock_forever:
                # Unlock it.
                traversing_object.unlock_exit(self)
            return True

        # Show the object's appearance.
        appearance = self.get_appearance(traversing_object)
        traversing_object.msg({"look_obj": appearance})
        return False

    def can_unlock(self, caller):
        """
        Unlock an exit.
        """
        # Only can unlock exits which match there conditions.
        return STATEMENT_HANDLER.match_condition(self.unlock_condition, caller,
                                                 self)

    def get_appearance(self, caller):
        """
        This is a convenient hook for a 'look'
        command to call.
        """
        # Get name and description.
        if caller.is_exit_unlocked(self.get_data_key()):
            # If is unlocked, use common appearance.
            return super(MudderyLockedExit, self).get_appearance(caller)

        can_unlock = self.can_unlock(caller)

        if self.auto_unlock and can_unlock:
            if self.unlock_forever:
                # Automatically unlock the exit when a character looking at it.
                caller.unlock_exit(self)

            # If is unlocked, use common appearance.
            return super(MudderyLockedExit, self).get_appearance(caller)

        cmds = []
        if can_unlock:
            # show unlock command
            verb = self.unlock_verb
            if not verb:
                verb = _("Unlock")
            cmds = [{"name": verb, "cmd": "unlock_exit", "args": self.dbref}]

        info = {
            "dbref": self.dbref,
            "name": self.name,
            "desc": self.locked_desc,
            "cmds": cmds
        }

        return info

    def get_available_commands(self, caller):
        """
        This returns a list of available commands.
        "args" must be a string without ' and ", usually it is self.dbref.
        """
        if caller.is_exit_unlocked(self.get_data_key()):
            # If is unlocked, use common commands.
            return super(MudderyLockedExit,
                         self).get_available_commands(caller)

        cmds = []
        can_unlock = STATEMENT_HANDLER.match_condition(self.unlock_condition,
                                                       caller, self)
        if can_unlock:
            # show unlock command
            verb = self.unlock_verb
            if not verb:
                verb = _("Unlock")
            cmds = [{"name": verb, "cmd": "unlock", "args": self.dbref}]

        return cmds
Example #20
0
class MudderySkill(TYPECLASS("OBJECT")):
    """
    A skill of the character.
    """
    typeclass_key = "SKILL"
    typeclass_name = _("Skill", "typeclasses")
    model_name = "skills"

    msg_escape = re.compile(r'%[%|n|c|t]')

    @staticmethod
    def escape_fun(word):
        """
        Change escapes to target words.
        """
        escape_word = word.group()
        char = escape_word[1]
        if char == "%":
            return char
        else:
            return "%(" + char + ")s"

    def at_object_creation(self):
        """
        Set default values.

        Returns:
            None
        """
        super(MudderySkill, self).at_object_creation()

        self.owner = None
        self.owner_dbref = None

        # set status
        if not self.attributes.has("owner"):
            self.db.owner_dbref = None
        if not self.attributes.has("cd_finish_time"):
            self.db.cd_finish_time = 0
        if not self.attributes.has("is_default"):
            self.db.is_default = False

    def at_init(self):
        """
        Load the skill's data.
        """
        super(MudderySkill, self).at_init()

        self.owner = None
        self.owner_dbref = self.db.owner_dbref
        if self.owner_dbref:
            self.owner = self.search_dbref(self.owner_dbref)

    def set_default(self, is_default):
        """
        Set this skill as the character's default skill.
        When skills in table default_skills changes, character's relative skills
        will change too.

        Args:
            is_default: (boolean) if the is default or not.
        """
        self.db.is_default = is_default

    def is_default(self):
        """
        Check if this skill is the character's default skill.

        Returns:
            (boolean) is default or not
        """
        return self.db.is_default

    def after_data_loaded(self):
        """
        Set data_info to the object.

        Returns:
            None
        """
        super(MudderySkill, self).after_data_loaded()

        # set data
        self.function = getattr(self.system, "function", "")
        self.cd = getattr(self.system, "cd", 0)
        self.passive = getattr(self.system, "passive", False)
        self.main_type = getattr(self.system, "main_type", "")
        self.sub_type = getattr(self.system, "sub_type", "")

        message_model = getattr(self.system, "message", "")
        self.message_model = self.msg_escape.sub(self.escape_fun,
                                                 message_model)

    def get_available_commands(self, caller):
        """
        This returns a list of available commands.

        Args:
            caller: (object) command's caller

        Returns:
            commands: (list) a list of available commands
        """
        if self.passive:
            return []

        commands = [{
            "name": _("Cast"),
            "cmd": "castskill",
            "args": self.get_data_key()
        }]
        return commands

    def set_owner(self, owner):
        """
        Set the owner of the skill.

        Args:
            owner: (object) skill's owner

        Returns:
            None
        """
        self.owner = owner
        self.owner_dbref = owner.dbref
        self.db.owner_dbref = owner.dbref

        if not self.passive:
            # Set skill cd. Add gcd to new the skill.
            gcd = GAME_SETTINGS.get("global_cd")
            if gcd > 0:
                self.db.cd_finish_time = time.time() + gcd

    def cast_skill(self, target):
        """
        Cast this skill.

        Args:
            target: (object) skill's target.

        Returns:
            skill_cast: (dict) skill's result
        """
        skill_cast = {}
        not_available = self.check_available()
        if not_available:
            skill_cast = {"cast": not_available}
        else:
            results = self.do_skill(target)

            # set message
            skill_cast = {
                "caller": self.owner_dbref,
                "skill": self.get_data_key(),
                "main_type": self.main_type,
                "sub_type": self.sub_type,
                "cast": self.cast_message(target),
                "status": {
                    self.owner.dbref: self.owner.get_combat_status(),
                }
            }

            if target:
                skill_cast["target"] = target.dbref
                skill_cast["status"][target.dbref] = target.get_combat_status()

            if results:
                skill_cast["result"] = " ".join(results)

        return skill_cast

    def do_skill(self, target):
        """
        Do this skill.
        """
        # set cd
        if not self.passive:
            # set cd
            time_now = time.time()
            if self.cd > 0:
                self.db.cd_finish_time = time_now + self.cd

        # call skill function
        return STATEMENT_HANDLER.do_skill(self.function, self.owner, target)

    def check_available(self):
        """
        Check this skill.

        Returns:
            message: (string) If the skill is not available, returns a string of reason.
                     If the skill is available, return "".
        """
        if self.is_cooling_down():
            return _("{C%s{n is not ready yet!") % self.get_name()

        return ""

    def is_available(self, passive):
        """
        If this skill is available.

        Args:
            passive: (boolean) cast a passive skill.

        Returns:
            (boolean) available or not.
        """
        if not passive and self.passive:
            return False

        if self.is_cooling_down():
            return False

        return True

    def is_cooling_down(self):
        """
        If this skill is cooling down.
        """
        if self.cd > 0:
            if self.db.cd_finish_time:
                if time.time() < self.db.cd_finish_time:
                    return True
        return False

    def get_remain_cd(self):
        """
        Get skill's CD.

        Returns:
            (float) Remain CD in seconds.
        """
        remain_cd = self.db.cd_finish_time - time.time()
        if remain_cd < 0:
            remain_cd = 0
        return remain_cd

    def cast_message(self, target):
        """
        Create skill's result message.
        """
        caller_name = ""
        target_name = ""
        message = ""

        if self.owner:
            caller_name = self.owner.get_name()

        if target:
            target_name = target.get_name()

        if self.message_model:
            values = {"n": self.name, "c": caller_name, "t": target_name}
            message = self.message_model % values

        return message

    def get_appearance(self, caller):
        """
        This is a convenient hook for a 'look'
        command to call.
        """
        info = super(MudderySkill, self).get_appearance(caller)

        info["passive"] = self.passive
        info["cd_remain"] = self.get_remain_cd()

        return info
Example #21
0
class MudderyShop(TYPECLASS("OBJECT")):
    """
    A shop.
    """
    typeclass_key = "SHOP"
    typeclass_name = _("Shop", "typeclasses")
    model_name = "shops"

    def at_object_creation(self):
        """
        Called once, when this object is first created. This is the
        normal hook to overload for most object types.

        It will be called when swap its typeclass, so it must keep
        old values.
        """
        super(MudderyShop, self).at_object_creation()

        # set default values
        self.db.owner = None

        if not self.attributes.has("goods"):
            self.db.goods = {}

    def at_object_delete(self):
        """
        Called just before the database object is permanently
        delete()d from the database. If this method returns False,
        deletion is aborted.

        All goods will be removed too.
        """
        result = super(MudderyShop, self).at_object_delete()
        if not result:
            return result

        # delete all goods
        for goods in self.db.goods.values():
            goods.delete()

        return True

    def after_data_loaded(self):
        """
        Set data_info to the object.

        Returns:
            None
        """
        super(MudderyShop, self).after_data_loaded()

        # load shop goods
        self.load_goods()

        self.verb = getattr(self.system, "verb", None)

    def load_goods(self):
        """
        Load shop goods.
        """
        # shops records
        goods_records = ShopGoods.get(self.get_data_key())

        goods_keys = set([record.key for record in goods_records])

        # search current goods
        current_goods = {}
        for key, obj in self.db.goods.items():
            if key in goods_keys:
                current_goods[key] = obj
            else:
                # remove goods that is not in goods_keys
                obj.delete()

        # add new goods
        for goods_record in goods_records:
            goods_key = goods_record.key
            if goods_key not in current_goods:
                # Create shop_goods object.
                goods_obj = build_object(goods_key)
                if not goods_obj:
                    logger.log_errmsg("Can't create goods: %s" % goods_key)
                    continue

                current_goods[goods_key] = goods_obj

        self.db.goods = current_goods

    def set_owner(self, owner):
        """
        Set the owner of the shop.

        :param owner:
        :return:
        """
        self.db.owner = owner

    def show_shop(self, caller):
        """
        Send shop data to the caller.

        Args:
            caller (obj): the custom
        """
        if not caller:
            return

        info = self.return_shop_info(caller)
        caller.msg({"shop": info})

    def return_shop_info(self, caller):
        """
        Get shop information.

        Args:
            caller (obj): the custom
        """
        info = {
            "dbref": self.dbref,
            "name": self.get_name(),
            "desc": self.get_desc(caller),
        }

        icon = self.icon
        if not icon and self.db.owner:
            icon = self.db.owner.icon
        info["icon"] = icon

        goods_list = self.return_shop_goods(caller)
        info["goods"] = goods_list

        return info

    def return_shop_goods(self, caller):
        """
        Get shop's information.

        Args:
            caller (obj): the custom
        """
        goods_list = []

        # Get shop goods
        for obj in self.db.goods.values():
            if not obj.is_available(caller):
                continue

            goods = {
                "dbref": obj.dbref,
                "name": obj.name,
                "desc": obj.desc,
                "number": obj.number,
                "price": obj.price,
                "unit": obj.unit_name,
                "icon": obj.icon
            }

            goods_list.append(goods)

        return goods_list
Example #22
0
    def receive_objects(self, obj_list, mute=False):
        """
        Add objects to the inventory.

        Args:
            obj_list: (list) a list of object keys and there numbers.
                             list item: {"object": object's key
                                         "number": object's number}
            mute: (boolean) do not send messages to the owner

        Returns:
            (list) a list of objects that not have been received and their reasons.
            [{
                "key": key,
                "name": name,
                "level": level,
                "number": number,
                "icon": icon,
                "reject": reason,
            }]
        """
        objects = []  # objects that have been accepted

        # check what the character has now
        inventory = {}
        for item in self.contents:
            key = item.get_data_key()
            if key in inventory:
                # if the character has more than one item of the same kind,
                # get the smallest stack.
                if inventory[key].db.number > item.db.number:
                    inventory[key] = item
            else:
                inventory[key] = item

        for obj in obj_list:
            key = obj["object"]
            level = obj.get("level")
            available = obj["number"]
            name = ""
            icon = ""
            number = available
            accepted = 0
            reject = False
            unique = False

            if number == 0:
                # it is an empty object
                if key in inventory:
                    # already has this object
                    continue

                object_record = None
                try:
                    common_model_name = TYPECLASS("COMMON_OBJECT").model_name
                    object_record = WorldData.get_table_data(common_model_name,
                                                             key=key)
                    object_record = object_record[0]
                except Exception as e:
                    pass

                if not object_record:
                    # can not find object's data record
                    continue

                if object_record.can_remove:
                    # remove this empty object
                    continue

                # create a new content
                new_obj = build_object(key, level=level)
                if not new_obj:
                    reject = _("Can not get %s.") % key
                else:
                    name = new_obj.get_name()
                    icon = new_obj.icon

                # move the new object to the character
                if not new_obj.move_to(self, quiet=True, emit_to_obj=self):
                    new_obj.delete()
                    reject = _("Can not get %s.") % name
            else:
                # common number
                # if already has this kind of object
                if key in inventory:
                    # add to current object
                    name = inventory[key].name
                    icon = inventory[key].icon
                    unique = inventory[key].unique

                    add = number
                    if add > inventory[key].max_stack - inventory[
                            key].db.number:
                        add = inventory[key].max_stack - inventory[
                            key].db.number

                    if add > 0:
                        # increase stack number
                        inventory[key].increase_num(add)
                        number -= add
                        accepted += add

                # if does not have this kind of object, or stack is full
                while number > 0:
                    if unique:
                        # can not have more than one unique objects
                        reject = _("Can not get more %s.") % name
                        break

                    # create a new content
                    new_obj = build_object(key, level=level)
                    if not new_obj:
                        reject = _("Can not get %s.") % name
                        break

                    name = new_obj.get_name()
                    icon = new_obj.icon
                    unique = new_obj.unique

                    # move the new object to the character
                    if not new_obj.move_to(self, quiet=True, emit_to_obj=self):
                        new_obj.delete()
                        reject = _("Can not get %s.") % name
                        break

                    # Get the number that actually added.
                    add = number
                    if add > new_obj.max_stack:
                        add = new_obj.max_stack

                    if add <= 0:
                        break

                    new_obj.increase_num(add)
                    number -= add
                    accepted += add

            objects.append({
                "key": key,
                "name": name,
                "icon": icon,
                "number": accepted,
                "reject": reject,
            })

        if not mute:
            # Send results to the player.
            message = {"get_objects": objects}
            self.msg(message)

        self.show_inventory()

        # call quest handler
        for item in objects:
            if not item["reject"]:
                self.quest_handler.at_objective(defines.OBJECTIVE_OBJECT,
                                                item["key"], item["number"])

        return objects
Example #23
0
class MudderyPlayerCharacter(TYPECLASS("CHARACTER")):
    """
    The Character defaults to implementing some of its hook methods with the
    following standard functionality:

    at_basetype_setup - always assigns the DefaultCmdSet to this object type
                    (important!)sets locks so character cannot be picked up
                    and its commands only be called by itself, not anyone else.
                    (to change things, use at_object_creation() instead)
    at_after_move - launches the "look" command
    at_post_puppet(player) -  when Player disconnects from the Character, we
                    store the current location, so the "unconnected" character
                    object does not need to stay on grid but can be given a
                    None-location while offline.
    at_pre_puppet - just before Player re-connects, retrieves the character's
                    old location and puts it back on the grid with a "charname
                    has connected" message echoed to the room

    """
    typeclass_key = "PLAYER_CHARACTER"
    typeclass_name = _("Player Character", "typeclasses")
    model_name = "player_characters"

    # initialize all handlers in a lazy fashion
    @lazy_property
    def quest_handler(self):
        return QuestHandler(self)

    # attributes used in statements
    @lazy_property
    def statement_attr(self):
        return StatementAttributeHandler(self)

    def at_object_creation(self):
        """
        Called once, when this object is first created. This is the
        normal hook to overload for most object types.
            
        """
        super(MudderyPlayerCharacter, self).at_object_creation()

        # Set default data.
        if not self.attributes.has("nickname"):
            self.db.nickname = ""
        if not self.attributes.has("unlocked_exits"):
            self.db.unlocked_exits = set()
        if not self.attributes.has("revealed_map"):
            self.db.revealed_map = set()

        # set custom attributes
        if not self.attributes.has("attributes"):
            self.db.attributes = {}

    def at_object_delete(self):
        """
        called just before deleting an object.
        """
        # remove the character's honour
        HONOURS_MAPPER.remove_honour(self.id)

        # remove all quests
        self.quest_handler.remove_all()

        return super(MudderyPlayerCharacter, self).at_object_delete()

    def after_data_loaded(self):
        """
        """
        super(MudderyPlayerCharacter, self).after_data_loaded()

        self.solo_mode = GAME_SETTINGS.get("solo_mode")
        self.available_channels = {}

        # refresh data
        self.refresh_properties(True)

        # if it is dead, reborn at init.
        if not self.is_alive():
            if not self.db.is_combat_instance and self.reborn_time > 0:
                self.reborn()

    def move_to(self,
                destination,
                quiet=False,
                emit_to_obj=None,
                use_destination=True,
                to_none=False,
                move_hooks=True,
                **kwargs):
        """
        Moves this object to a new location.
        """
        if not quiet and self.solo_mode:
            # If in solo mode, move quietly.
            quiet = True

        return super(MudderyPlayerCharacter,
                     self).move_to(destination, quiet, emit_to_obj,
                                   use_destination, to_none, move_hooks)

    def at_object_receive(self, moved_obj, source_location, **kwargs):
        """
        Called after an object has been moved into this object.
        
        Args:
        moved_obj (Object): The object moved into this one
        source_location (Object): Where `moved_object` came from.
        
        """
        super(MudderyPlayerCharacter,
              self).at_object_receive(moved_obj, source_location)

        # send latest inventory data to player
        self.msg({"inventory": self.return_inventory()})

    def at_object_left(self, moved_obj, target_location):
        """
        Called after an object has been removed from this object.
        
        Args:
        moved_obj (Object): The object leaving
        target_location (Object): Where `moved_obj` is going.
        
        """
        super(MudderyPlayerCharacter,
              self).at_object_left(moved_obj, target_location)

        # send latest inventory data to player
        self.msg({"inventory": self.return_inventory()})

    def at_before_move(self, destination, **kwargs):
        """
        Called just before starting to move this object to
        destination.
        """
        # trigger event
        if self.has_account:
            self.location.event.at_character_move_out(self)

        return True

    def at_after_move(self, source_location):
        """
        We make sure to look around after a move.

        """
        self.msg({"msg": _("Moved to %s ...") % self.location.name})
        self.show_location()

        # trigger event
        if self.has_account:
            self.location.event.at_character_move_in(self)

    def at_post_puppet(self):
        """
        Called just after puppeting has been completed and all
        Player<->Object links have been established.

        """
        self.available_channels = self.get_available_channels()

        allow_commands = False
        if self.account:
            if self.is_superuser:
                allow_commands = True
            else:
                for perm in self.account.permissions.all():
                    if perm in settings.PERMISSION_COMMANDS:
                        allow_commands = True
                        break

        # Django's superuser even it is quelled.
        if not allow_commands:
            allow_commands = self.db_account and self.db_account.is_superuser

        # Send puppet info to the client first.
        output = {
            "dbref": self.dbref,
            "name": self.get_name(),
            "icon": getattr(self, "icon", None),
        }

        if allow_commands:
            output["allow_commands"] = True

        self.msg({"puppet": output})

        # send character's data to player
        message = {
            "status": self.return_status(),
            "equipments": self.return_equipments(),
            "inventory": self.return_inventory(),
            "skills": self.return_skills(),
            "quests": self.quest_handler.return_quests(),
            "revealed_map": self.get_revealed_map(),
            "channels": self.available_channels
        }
        self.msg(message)

        self.show_location()

        # notify its location
        if not self.solo_mode:
            if self.location:
                change = {"dbref": self.dbref, "name": self.get_name()}
                self.location.msg_contents({"player_online": change},
                                           exclude=[self])

        self.resume_last_dialogue()

        self.resume_combat()

        # Resume all scripts.
        scripts = self.scripts.all()
        for script in scripts:
            script.unpause()

    def at_pre_unpuppet(self):
        """
        Called just before beginning to un-connect a puppeting from
        this Player.
        """
        # Pause all scripts.
        scripts = self.scripts.all()
        for script in scripts:
            script.pause()

        if not self.solo_mode:
            # notify its location
            if self.location:
                change = {"dbref": self.dbref, "name": self.get_name()}
                self.location.msg_contents({"player_offline": change},
                                           exclude=self)

        MATCH_COMBAT_HANDLER.remove(self)

    def get_data_key(self, default=""):
        """
        Get data's key.

        Args:
            default: (string) default value if can not find the data key.
        """
        key = GAME_SETTINGS.get("default_player_character_key")
        if not key:
            key = self.attributes.get(key="key",
                                      category=settings.DATA_KEY_CATEGORY,
                                      strattr=True)
            if not key:
                key = default
        return key

    def set_nickname(self, nickname):
        """
        Set player character's nickname.
        """
        self.db.nickname = nickname

    def get_name(self):
        """
        Get player character's name.
        """
        # Use nick name instead of normal name.
        return self.db.nickname

    def get_available_commands(self, caller):
        """
        This returns a list of available commands.
        """
        commands = []
        if self.is_alive():
            commands.append({
                "name": _("Attack"),
                "cmd": "attack",
                "args": self.dbref
            })
        return commands

    def get_available_channels(self):
        """
        Get available channel's info.

        Returns:
            (dict) channels
        """
        channels = {}
        channel = ChannelDB.objects.get_channel(
            settings.DEFAULT_CHANNELS[0]["key"])
        if channel.has_connection(self):
            channels[channel.key] = {
                "type": "CHANNEL",
                "name": _("Public", category="channels"),
            }
        """
        commands = False
        if self.account:
            if self.is_superuser:
                commands = True
            else:
                for perm in self.account.permissions.all():
                    if perm in settings.PERMISSION_COMMANDS:
                        commands = True
                        break

        # Django's superuser even it is quelled.
        if not commands:
            commands = self.db_account and self.db_account.is_superuser

        if commands:
            channels["CMD"] = {
                "type": "CMD",
                "name": _("Cmd"),
            }
        """
        return channels

    def get_revealed_map(self):
        """
        Get the map that the character has revealed.
        Return value:
            {
                "rooms": {room1's key: {"name": name,
                                        "icon": icon,
                                        "area": area,
                                        "pos": position},
                          room2's key: {"name": name,
                                        "icon": icon,
                                        "area": area,
                                        "pos": position},
                          ...},
                "exits": {exit1's key: {"from": room1's key,
                                        "to": room2's key},
                          exit2's key: {"from": room3's key,
                                        "to": room4's key},
                          ...}
            }
        """
        rooms = {}
        exits = {}

        for room_key in self.db.revealed_map:
            # get room's information
            room = utils.search_obj_data_key(room_key)
            if room:
                room = room[0]
                rooms[room_key] = {
                    "name": room.get_name(),
                    "icon": room.icon,
                    "area": room.location and room.location.get_data_key(),
                    "pos": room.position
                }

                new_exits = room.get_exits()
                if new_exits:
                    exits.update(new_exits)

        for path in exits.values():
            # add room's neighbours
            if not path["to"] in rooms:
                neighbour = utils.search_obj_data_key(path["to"])
                if neighbour:
                    neighbour = neighbour[0]
                    rooms[neighbour.get_data_key()] = {
                        "name":
                        neighbour.get_name(),
                        "icon":
                        neighbour.icon,
                        "area":
                        neighbour.location
                        and neighbour.location.get_data_key(),
                        "pos":
                        neighbour.position
                    }

        return {"rooms": rooms, "exits": exits}

    def show_location(self):
        """
        show character's location
        """
        if self.location:
            location_key = self.location.get_data_key()
            area = self.location.location and self.location.location.get_appearance(
                self)

            msg = {"current_location": {"key": location_key, "area": area}}
            """
            reveal_map:
            {
                "rooms": {room1's key: {"name": name,
                                        "icon": icon,
                                        "area": area,
                                        "pos": position},
                          room2's key: {"name": name,
                                        "icon": icon,
                                        "area": area,
                                        "pos": position},
                          ...},
                "exits": {exit1's key: {"from": room1's key,
                                        "to": room2's key},
                          exit2's key: {"from": room3's key,
                                        "to": room4's key},
                          ...}
            }
            """
            reveal_map = None
            if not location_key in self.db.revealed_map:
                # reveal map
                self.db.revealed_map.add(self.location.get_data_key())

                rooms = {
                    location_key: {
                        "name":
                        self.location.get_name(),
                        "icon":
                        self.location.icon,
                        "area":
                        self.location.location
                        and self.location.location.get_data_key(),
                        "pos":
                        self.location.position
                    }
                }

                exits = self.location.get_exits()

                for path in exits.values():
                    # add room's neighbours
                    if not path["to"] in rooms:
                        neighbour = utils.search_obj_data_key(path["to"])
                        if neighbour:
                            neighbour = neighbour[0]

                            rooms[neighbour.get_data_key()] = {
                                "name":
                                neighbour.get_name(),
                                "icon":
                                neighbour.icon,
                                "area":
                                neighbour.location
                                and neighbour.location.get_data_key(),
                                "pos":
                                neighbour.position
                            }

                msg["reveal_map"] = {"rooms": rooms, "exits": exits}

            # get appearance
            appearance = self.location.get_appearance(self)
            appearance.update(self.location.get_surroundings(self))
            msg["look_around"] = appearance

            self.msg(msg)

    def load_default_objects(self):
        """
        Load character's default objects.
        """
        # get character's model name
        model_name = getattr(self.system, "model", None)
        if not model_name:
            model_name = self.get_data_key()

        # default objects
        object_records = DefaultObjects.get(model_name)

        # add new default objects
        obj_list = []
        for object_record in object_records:
            if not self.search_inventory(object_record.object):
                obj_list.append({
                    "object": object_record.object,
                    "level": object_record.level,
                    "number": object_record.number,
                })

        if obj_list:
            self.receive_objects(obj_list, mute=True)

    def receive_objects(self, obj_list, mute=False):
        """
        Add objects to the inventory.

        Args:
            obj_list: (list) a list of object keys and there numbers.
                             list item: {"object": object's key
                                         "number": object's number}
            mute: (boolean) do not send messages to the owner

        Returns:
            (list) a list of objects that not have been received and their reasons.
            [{
                "key": key,
                "name": name,
                "level": level,
                "number": number,
                "icon": icon,
                "reject": reason,
            }]
        """
        objects = []  # objects that have been accepted

        # check what the character has now
        inventory = {}
        for item in self.contents:
            key = item.get_data_key()
            if key in inventory:
                # if the character has more than one item of the same kind,
                # get the smallest stack.
                if inventory[key].db.number > item.db.number:
                    inventory[key] = item
            else:
                inventory[key] = item

        for obj in obj_list:
            key = obj["object"]
            level = obj.get("level")
            available = obj["number"]
            name = ""
            icon = ""
            number = available
            accepted = 0
            reject = False
            unique = False

            if number == 0:
                # it is an empty object
                if key in inventory:
                    # already has this object
                    continue

                object_record = None
                try:
                    common_model_name = TYPECLASS("COMMON_OBJECT").model_name
                    object_record = WorldData.get_table_data(common_model_name,
                                                             key=key)
                    object_record = object_record[0]
                except Exception as e:
                    pass

                if not object_record:
                    # can not find object's data record
                    continue

                if object_record.can_remove:
                    # remove this empty object
                    continue

                # create a new content
                new_obj = build_object(key, level=level)
                if not new_obj:
                    reject = _("Can not get %s.") % key
                else:
                    name = new_obj.get_name()
                    icon = new_obj.icon

                # move the new object to the character
                if not new_obj.move_to(self, quiet=True, emit_to_obj=self):
                    new_obj.delete()
                    reject = _("Can not get %s.") % name
            else:
                # common number
                # if already has this kind of object
                if key in inventory:
                    # add to current object
                    name = inventory[key].name
                    icon = inventory[key].icon
                    unique = inventory[key].unique

                    add = number
                    if add > inventory[key].max_stack - inventory[
                            key].db.number:
                        add = inventory[key].max_stack - inventory[
                            key].db.number

                    if add > 0:
                        # increase stack number
                        inventory[key].increase_num(add)
                        number -= add
                        accepted += add

                # if does not have this kind of object, or stack is full
                while number > 0:
                    if unique:
                        # can not have more than one unique objects
                        reject = _("Can not get more %s.") % name
                        break

                    # create a new content
                    new_obj = build_object(key, level=level)
                    if not new_obj:
                        reject = _("Can not get %s.") % name
                        break

                    name = new_obj.get_name()
                    icon = new_obj.icon
                    unique = new_obj.unique

                    # move the new object to the character
                    if not new_obj.move_to(self, quiet=True, emit_to_obj=self):
                        new_obj.delete()
                        reject = _("Can not get %s.") % name
                        break

                    # Get the number that actually added.
                    add = number
                    if add > new_obj.max_stack:
                        add = new_obj.max_stack

                    if add <= 0:
                        break

                    new_obj.increase_num(add)
                    number -= add
                    accepted += add

            objects.append({
                "key": key,
                "name": name,
                "icon": icon,
                "number": accepted,
                "reject": reject,
            })

        if not mute:
            # Send results to the player.
            message = {"get_objects": objects}
            self.msg(message)

        self.show_inventory()

        # call quest handler
        for item in objects:
            if not item["reject"]:
                self.quest_handler.at_objective(defines.OBJECTIVE_OBJECT,
                                                item["key"], item["number"])

        return objects

    def get_object_number(self, obj_key):
        """
        Get the number of this object.
        Args:
            obj_key: (String) object's key

        Returns:
            int: object number
        """
        objects = self.search_inventory(obj_key)

        # get total number
        sum = 0
        for obj in objects:
            obj_num = obj.get_number()
            sum += obj_num

        return sum

    def can_get_object(self, obj_key, number):
        """
        Check if the character can get these objects.

        Args:
            obj_key: (String) object's key
            number: (int) object's number

        Returns:
            boolean: can get

        Notice:
            If the character does not have this object, the return will be always true,
            despite of the number!
        """
        objects = self.search_inventory(obj_key)

        if not objects:
            return True

        obj = objects[0]
        if not obj.unique:
            return True

        if obj.get_number() + number <= obj.max_stack:
            return True

        return False

    def use_object(self, obj, number=1):
        """
        Use an object.

        Args:
            obj: (object) object to use
            number: (int) number to use

        Returns:
            result: (string) the description of the result
        """
        if not obj:
            return _("Can not find this object.")

        if obj.db.number < number:
            return _("Not enough number.")

        # take effect
        try:
            result, used = obj.take_effect(self, number)
            if used > 0:
                # remove used object
                self.remove_object(obj.get_data_key(), used)
            return result
        except Exception as e:
            ostring = "Can not use %s: %s" % (obj.get_data_key(), e)
            logger.log_tracemsg(ostring)

        return _("No effect.")

    def remove_objects(self, obj_list):
        """
        Remove objects from the inventory.

        Args:
            obj_list: (list) a list of object keys and there numbers.
                             list item: {"object": object's key
                                         "number": object's number}

        Returns:
            boolean: success
        """
        success = True
        for item in obj_list:
            if not self.remove_object(item["object"], item["number"], True):
                success = False

        self.show_inventory()
        return success

    def remove_object(self, obj_key, number, mute=False):
        """
        Remove objects from the inventory.

        Args:
            obj_key: object's key
            number: object's number
            mute: send inventory information

        Returns:
            boolean: success
        """
        objects = self.search_inventory(obj_key)

        # get total number
        sum = 0
        for obj in objects:
            obj_num = obj.get_number()
            sum += obj_num

        if sum < number:
            return False

        # remove objects
        to_remove = number
        try:
            for obj in objects:
                obj_num = obj.get_number()
                if obj_num > 0:
                    if obj_num >= to_remove:
                        obj.decrease_num(to_remove)
                        to_remove = 0
                    else:
                        obj.decrease_num(obj_num)
                        to_remove -= obj_num

                    if obj.get_number() <= 0:
                        # If this object can be removed from the inventor.
                        if obj.can_remove:
                            # if it is an equipment, take off it first
                            if getattr(obj, "equipped", False):
                                self.take_off_equipment(obj)
                            obj.delete()

                if to_remove <= 0:
                    break
        except Exception as e:
            logger.log_tracemsg("Can not remove object %s: %s" % (obj_key, e))
            return False

        if to_remove > 0:
            logger.log_err("Remove object error: %s" % obj_key)
            return False

        if not mute:
            self.show_inventory()

        return True

    def search_inventory(self, obj_key):
        """
        Search specified object in the inventory.
        """
        result = [
            item for item in self.contents if item.get_data_key() == obj_key
        ]
        return result

    def show_inventory(self):
        """
        Send inventory data to player.
        """
        inv = self.return_inventory()
        self.msg({"inventory": inv})

    def return_inventory(self):
        """
        Get inventory's data.
        """
        inv = []
        for item in self.contents:
            info = {
                "dbref": item.dbref,  # item's dbref
                "name": item.name,  # item's name
                "number": item.db.number,  # item's number
                "desc": item.get_desc(self),  # item's desc
                "can_remove": item.can_remove,
                "icon": getattr(item, "icon", None)
            }  # item's icon

            if getattr(item, "equipped", False):
                info["equipped"] = item.equipped
            inv.append(info)

        # sort by created time
        inv.sort(key=lambda x: x["dbref"])

        return inv

    def show_status(self):
        """
        Send status to player.
        """
        status = self.return_status()
        self.msg({"status": status})

    def return_status(self):
        """
        Get character's status.
        """
        status = {}
        status["level"] = {"name": _("LEVEL"), "value": self.db.level}

        for key, info in self.get_properties_info().items():
            status[key] = {
                "name": info["name"],
                "value": getattr(self.prop, key)
            }

        return status

    def show_equipments(self):
        """
        Send equipments to player.
        """
        equipments = self.return_equipments()
        self.msg({"equipments": equipments})

    def return_equipments(self):
        """
        Get equipments' data.
        """
        equipments = {}
        for position in self.db.equipments:
            # in order of positions
            info = None
            if self.db.equipments[position]:
                dbref = self.db.equipments[position]
                for obj in self.contents:
                    if obj.dbref == dbref:
                        info = {
                            "dbref": obj.dbref,
                            "name": obj.name,
                            "desc": obj.get_desc(self),
                            "icon": obj.icon,
                        }
            equipments[position] = info

        return equipments

    def equip_object(self, obj):
        """
        Equip an object.
        args: obj(object): the equipment object.
        """
        if obj.location != self:
            raise MudderyError(_("Can not find this equipment."))

        type = obj.type
        position = obj.position

        if position not in self.db.equipments:
            raise MudderyError(_("Can not equip it on this position."))

        if not EQUIP_TYPE_HANDLER.can_equip(self.db.career, type):
            raise MudderyError(_("Can not use this equipment."))

        # Take off old equipment
        if self.db.equipments[position]:
            dbref = self.db.equipments[position]

            for content in self.contents:
                if content.dbref == dbref:
                    content.equipped = False

        # Put on new equipment, store object's dbref.
        self.db.equipments[position] = obj.dbref

        # Set object's attribute 'equipped' to True
        obj.equipped = True

        # reset character's attributes
        self.refresh_properties(True)

        message = {
            "status": self.return_status(),
            "equipments": self.return_equipments(),
            "inventory": self.return_inventory()
        }
        self.msg(message)

        return

    def take_off_position(self, position):
        """
        Take off an object from position.
        """
        if not position in self.db.equipments:
            raise MudderyError(_("Can not find this equipment."))

        if not self.db.equipments[position]:
            raise MudderyError(_("Can not find this equipment."))

        # Set object's attribute 'equipped' to False
        dbref = self.db.equipments[position]

        for obj in self.contents:
            if obj.dbref == dbref:
                obj.equipped = False
                find = True

        self.db.equipments[position] = None

        # reset character's attributes
        self.refresh_properties(True)

        message = {
            "status": self.return_status(),
            "equipments": self.return_equipments(),
            "inventory": self.return_inventory()
        }
        self.msg(message)

    def take_off_equipment(self, equipment):
        """
        Take off an equipment.
        args: equipment(object): the equipment object.
        """
        if equipment.location != self:
            raise MudderyError(_("Can not find this equipment."))

        if equipment.position in self.db.equipments:
            self.db.equipments[equipment.position] = None

        # Set object's attribute 'equipped' to False
        equipment.equipped = False

        # reset character's attributes
        self.refresh_properties(True)

        message = {
            "status": self.return_status(),
            "equipments": self.return_equipments(),
            "inventory": self.return_inventory()
        }
        self.msg(message)

    def lock_exit(self, exit):
        """
        Lock an exit. Remove the exit's key from the character's unlock list.
        """
        exit_key = exit.get_data_key()
        if not self.is_exit_unlocked(exit_key):
            return

        self.db.unlocked_exits.remove(exit_key)
        print(self.db.unlocked_exits)

    def unlock_exit(self, exit):
        """
        Unlock an exit. Add the exit's key to the character's unlock list.
        """
        exit_key = exit.get_data_key()
        if self.is_exit_unlocked(exit_key):
            return True

        if not exit.can_unlock(self):
            self.msg({"msg": _("Can not open this exit.")})
            return False

        self.db.unlocked_exits.add(exit_key)
        return True

    def is_exit_unlocked(self, exit_key):
        """
        Whether the exit is unlocked.
        """
        return exit_key in self.db.unlocked_exits

    def show_skills(self):
        """
        Send skills to player.
        """
        skills = self.return_skills()
        self.msg({"skills": skills})

    def return_skills(self):
        """
        Get skills' data.
        """
        skills = []

        for key, skill in self.db.skills.items():
            skills.append(skill.get_appearance(self))

        return skills

    def resume_combat(self):
        """
        Resume unfinished combat.

        Returns:
            None
        """
        combat_handler = getattr(self.ndb, "combat_handler", None)
        if combat_handler:
            if not combat_handler.is_finished():
                # show combat infomation
                combat_handler.show_combat(self)
            else:
                self.leave_combat()

    def combat_result(self, combat_type, result, opponents=None, rewards=None):
        """
        Set the combat result.

        :param combat_type: combat's type
        :param result: defines.COMBAT_WIN, defines.COMBAT_LOSE, or defines.COMBAT_DRAW
        :param opponents: combat opponents
        :param rewards: combat rewards
        """
        combat_result = {
            "type": combat_type.value,
            "result": result,
            "rewards": {},
        }

        # get rewards
        if rewards:
            if "exp" in rewards and rewards["exp"]:
                exp = rewards["exp"]
                self.add_exp(exp)
                combat_result["rewards"]["exp"] = exp

            # give objects to winner
            if "loots" in rewards and rewards["loots"]:
                get_objects = self.receive_objects(rewards["loots"], mute=True)
                combat_result["rewards"]["get_objects"] = get_objects

            # honours
            if "honour" in rewards and rewards["honour"]:
                combat_result["rewards"]["honour"] = rewards["honour"]

        self.msg({"combat_finish": combat_result})

        if combat_type == CombatType.NORMAL:
            # normal combat
            # trigger events
            if result == defines.COMBAT_WIN:
                for opponent in opponents:
                    opponent.event.at_character_kill(self)
                    opponent.event.at_character_die()

                # call quest handler
                for opponent in opponents:
                    self.quest_handler.at_objective(defines.OBJECTIVE_KILL,
                                                    opponent.get_data_key())
            elif result == defines.COMBAT_LOSE:
                self.die(opponents)
        elif combat_type == CombatType.HONOUR:
            if result == defines.COMBAT_WIN:
                self.honour_win()
            elif result == defines.COMBAT_LOSE:
                self.honour_lose()

        # show status
        self.show_status()
        self.show_location()

    def die(self, killers):
        """
        This character is killed. Move it to it's home.
        """

        # player's character can always reborn
        if self.reborn_time < 1:
            self.reborn_time = 1

        super(MudderyPlayerCharacter, self).die(killers)

        self.msg({"msg": _("You died.")})

        if self.reborn_time > 0:
            self.msg({
                "msg": _("You will be reborn in {C%(s)s{n seconds.") % {
                    's': self.reborn_time
                }
            })

    def honour_win(self):
        """
        The character win in an honour combat.
        """
        # Recover properties.
        self.recover()
        self.show_status()

    def honour_lose(self):
        """
        The character lost in an honour combat.
        """
        # Recover properties.
        self.recover()
        self.show_status()

    def reborn(self):
        """
        Reborn after being killed.
        """
        # Reborn at its home.
        home = None
        default_home_key = GAME_SETTINGS.get("default_player_home_key")
        if default_home_key:
            rooms = utils.search_obj_data_key(default_home_key)
            if rooms:
                home = rooms[0]

        if not home:
            rooms = search.search_object(settings.DEFAULT_HOME)
            if rooms:
                home = rooms[0]

        if home:
            self.move_to(home, quiet=True)

        # Recover properties.
        self.recover()
        self.show_status()

        if home:
            self.msg({"msg": _("You are reborn at {C%s{n.") % home.get_name()})
        else:
            self.msg({"msg": _("You are reborn.")})

    def save_current_dialogues(self, dialogues, npc):
        """
        Save player's current dialogues.

        Args:
            dialogues: the current dialogues
            npc: NPC whom the player is talking to.

        Returns:
            None
        """
        if not GAME_SETTINGS.get("auto_resume_dialogues"):
            # Can not auto resume dialogues.
            return

        if not dialogues:
            self.clear_current_dialogue()
            return

        # Save the dialogue's id.
        dialogues = [d["dialogue"] for d in dialogues]

        npc_key = None
        if npc:
            npc_key = npc.get_data_key()

        location_key = None
        if self.location:
            location_key = self.location.get_data_key()

        self.db.current_dialogue = {
            "dialogues": dialogues,
            "npc": npc_key,
            "location": location_key
        }

        return

    def clear_current_dialogue(self):
        """
        Clear player's current dialogues.

        Returns:
            None
        """
        self.db.current_dialogue = None
        return

    def resume_last_dialogue(self):
        """
        Restore player's dialogues when he return to game.

        Returns:
            None
        """
        if not GAME_SETTINGS.get("auto_resume_dialogues"):
            # Can not auto resume dialogues.
            return

        if not self.db.current_dialogue:
            return

        current = self.db.current_dialogue

        if not current["dialogues"]:
            return

        # Check dialogue's location
        if self.location.get_data_key() != current["location"]:
            # If player's location has changed, return.
            return

        # Check npc.
        npc_talking = None
        if current["npc"]:
            npc_list = utils.search_obj_data_key(current["npc"])
            npc_in_location = [
                npc for npc in npc_list if npc.location == self.location
            ]
            if not npc_in_location:
                # If the NPC has left it's location, return.
                return
            npc_talking = npc_in_location[0]

        dialogues = [
            DIALOGUE_HANDLER.get_dialogue(d) for d in current["dialogues"]
        ]
        dialogues = DIALOGUE_HANDLER.create_output_sentences(
            dialogues, self, npc_talking)
        self.msg({"dialogue": dialogues})
        return

    def talk_to_npc(self, npc):
        """
        Talk to an NPC.

        Args:
            npc: NPC's object.

        Returns:
            None
        """
        # Set caller's target.
        self.set_target(npc)

        # Get NPC's dialogue list.
        dialogues = DIALOGUE_HANDLER.get_npc_dialogues(self, npc)

        self.save_current_dialogues(dialogues, npc)
        self.msg({"dialogue": dialogues})

    def show_dialogue(self, dlg_key, npc):
        """
        Show a dialogue.

        Args:
            dlg_key: dialogue's key.
            npc: (optional) NPC's object.

        Returns:
            None
        """
        # Get next sentences_list.
        dialogue = DIALOGUE_HANDLER.get_dialogues_by_key(dlg_key, npc)

        # Send the dialogue to the player.
        self.save_current_dialogues(dialogue, npc)
        self.msg({"dialogue": dialogue})

    def finish_dialogue(self, dlg_key, npc):
        """
        Continue current dialogue.

        Args:
            dlg_key: current dialogue's key.
            npc: (optional) NPC's object.

        Returns:
            None
        """
        if GAME_SETTINGS.get("auto_resume_dialogues"):
            # Check current dialogue.
            if not self.db.current_dialogue:
                return

            if dlg_key not in self.db.current_dialogue["dialogue"]:
                # Can not find specified dialogue in current dialogues.
                return

        try:
            # Finish current dialogue
            DIALOGUE_HANDLER.finish_dialogue(dlg_key, self, npc)
        except Exception as e:
            ostring = "Can not finish dialogue %s: %s" % (dlg_key, e)
            logger.log_tracemsg(ostring)

        # Get next dialogue.
        next_dialogues = DIALOGUE_HANDLER.get_next_dialogues(
            dlg_key, self, npc)

        # Send dialogues_list to the player.
        self.save_current_dialogues(next_dialogues, npc)
        self.msg({"dialogue": next_dialogues})
        if not next_dialogues:
            # dialogue finished, refresh surroundings
            self.show_location()

    def add_exp(self, exp):
        """
        Add character's exp.
        Args:
            exp: (number) the exp value to add.
        Returns:
            None
        """
        super(MudderyPlayerCharacter, self).add_exp(exp)

        self.msg({"get_exp": {"exp": exp}})

    def level_up(self):
        """
        Upgrade level.

        Returns:
            None
        """
        super(MudderyPlayerCharacter, self).level_up()

        # notify the player
        self.msg({
            "msg":
            _("{C%s upgraded to level %s.{n") %
            (self.get_name(), self.db.level)
        })

    def get_message(self, caller, message):
        """
        Receive a message from a character.

        :param caller: talker.
        :param message: content.
        """
        output = {
            "type": ConversationType.PRIVATE.value,
            "channel": self.get_name(),
            "from_dbref": caller.dbref,
            "from_name": caller.get_name(),
            "msg": message
        }
        self.msg({"conversation": output})
        caller.msg({"conversation": output})

    def at_object_delete(self):
        """
        Called just before the database object is permanently
        delete()d from the database. If this method returns False,
        deletion is aborted.

        All skills, contents will be removed too.
        """
        result = super(MudderyPlayerCharacter, self).at_object_delete()
        if not result:
            return result

        self.quest_handler.remove_all()
        return True

    def show_rankings(self):
        """
        Show character's rankings.
        """
        honour_settings = HonourSettings.get_first_data()
        top_rankings = HONOURS_MAPPER.get_top_rankings(
            honour_settings.top_rankings_number)
        nearest_rankings = HONOURS_MAPPER.get_nearest_rankings(
            self, honour_settings.nearest_rankings_number)

        rankings = top_rankings
        rankings.extend([
            char_id for char_id in nearest_rankings
            if char_id not in top_rankings
        ])

        characters = [
            self.search_dbref("#%s" % char_id) for char_id in rankings
        ]
        data = [{
            "name": char.get_name(),
            "dbref": char.dbref,
            "ranking": HONOURS_MAPPER.get_ranking(char),
            "honour": HONOURS_MAPPER.get_honour(char)
        } for char in characters if char]
        self.msg({"rankings": data})
Example #24
0
 def __init__(self):
     self.model_name = TYPECLASS("EXIT").model_name
     self.model = apps.get_model(settings.WORLD_DATA_APP, self.model_name)
     self.objects = self.model.objects
     self.object_model_name = TYPECLASS("OBJECT").model_name
Example #25
0
class MudderyQuest(TYPECLASS("OBJECT")):
    """
    This class controls quest's objectives. Hooks are called when a character doing some things.
    """
    typeclass_key = "QUEST"
    typeclass_name = _("Quest", "typeclasses")
    model_name = "quests"

    # initialize loot handler in a lazy fashion
    @lazy_property
    def loot_handler(self):
        return LootHandler(self, QuestLootList.get(self.get_data_key()))

    def at_object_creation(self):
        """
        Set accomplished objectives to empty.
        """
        super(MudderyQuest, self).at_object_creation()

        if not self.attributes.has("owner"):
            self.db.owner = None
        if not self.attributes.has("accomplished"):
            self.db.accomplished = {}

    def set_owner(self, owner):
        """
        Set the owner of the skill.
        """
        self.db.owner = owner

    def after_data_loaded(self):
        """
        Load quest's data from db.
        """
        super(MudderyQuest, self).after_data_loaded()

        self.objectives = {}
        self.not_accomplished = {}

        key = self.get_data_key()
        if not key:
            return

        # Get objectives.
        obj_records = QuestObjectives.get(key)

        for obj_record in obj_records:
            objective_type = obj_record.type
            objective = {
                "ordinal": obj_record.ordinal,
                "type": objective_type,
                "object": obj_record.object,
                "number": obj_record.number,
                "desc": obj_record.desc
            }
            self.objectives[obj_record.ordinal] = objective

            accomplished = self.db.accomplished.get(key, 0)
            if accomplished < obj_record.number:
                if not objective_type in self.not_accomplished:
                    self.not_accomplished[objective_type] = [
                        obj_record.ordinal
                    ]
                else:
                    self.not_accomplished[objective_type].append(
                        obj_record.ordinal)

    def get_appearance(self, caller):
        """
        This is a convenient hook for a 'look'
        command to call.
        """
        # Get name, description and available commands.
        info = super(MudderyQuest, self).get_appearance(caller)

        info["objectives"] = self.return_objectives()
        return info

    def get_available_commands(self, caller):
        """
        This returns a list of available commands.
        """
        commands = []
        if GAME_SETTINGS.get("can_give_up_quests"):
            commands.append({
                "name": _("Give Up"),
                "cmd": "giveup_quest",
                "args": self.get_data_key()
            })
        return commands

    def return_objectives(self):
        """
        Get the information of all objectives.
        Set desc to an objective can hide the details of the objective.
        """
        output = []

        for ordinal, objective in self.objectives.items():
            desc = objective["desc"]
            if desc:
                # If an objective has desc, use its desc.
                output.append({"ordinal": ordinal, "desc": objective["desc"]})
            else:
                # Or make a desc by other data.
                obj_num = objective["number"]
                accomplished = self.db.accomplished.get(ordinal, 0)

                if objective["type"] == defines.OBJECTIVE_TALK:
                    # talking
                    target = _("Talk to")
                    name = DIALOGUE_HANDLER.get_npc_name(objective["object"])

                    output.append({
                        "ordinal": ordinal,
                        "target": target,
                        "object": name,
                        "accomplished": accomplished,
                        "total": obj_num,
                    })

                elif objective["type"] == defines.OBJECTIVE_OBJECT:
                    # getting
                    target = _("Get")

                    # Get the name of the objective object.
                    object_key = objective["object"]
                    model_name = TYPECLASS("OBJECT").model_name

                    # Get record.
                    try:
                        record = WorldData.get_table_data(model_name,
                                                          key=object_key)
                        record = record[0]
                        name = record.name
                    except Exception as e:
                        logger.log_err("Can not find the quest object: %s" %
                                       object_key)
                        continue

                    output.append({
                        "ordinal": ordinal,
                        "target": target,
                        "object": name,
                        "accomplished": accomplished,
                        "total": obj_num,
                    })

                elif self.objectives[ordinal][
                        "type"] == defines.OBJECTIVE_KILL:
                    # getting
                    target = _("Kill")

                    # Get the name of the objective character.
                    object_key = self.objectives[ordinal]["object"]
                    model_name = TYPECLASS("OBJECT").model_name

                    # Get record.
                    try:
                        record = WorldData.get_table_data(model_name,
                                                          key=object_key)
                        record = record[0]
                        name = record.name
                    except Exception as e:
                        logger.log_err("Can not find the quest object: %s" %
                                       object_key)
                        continue

                    output.append({
                        "ordinal": ordinal,
                        "target": target,
                        "object": name,
                        "accomplished": accomplished,
                        "total": obj_num,
                    })

        return output

    def is_accomplished(self):
        """
        All objectives of this quest are accomplished.
        """
        for ordinal in self.objectives:
            obj_num = self.objectives[ordinal]["number"]
            accomplished = self.db.accomplished.get(ordinal, 0)

            if accomplished < obj_num:
                return False

        return True

    def turn_in(self):
        """
        Turn in a quest, do its action.
        """
        owner = self.db.owner

        # get rewards
        obj_list = self.loot_handler.get_obj_list(owner)
        if obj_list:
            # give objects to winner
            owner.receive_objects(obj_list)

        # do quest's action
        action = getattr(self.system, "action", None)
        if action:
            STATEMENT_HANDLER.do_action(action, owner, None)

        # remove objective objects
        obj_list = []
        for ordinal in self.objectives:
            if self.objectives[ordinal]["type"] == defines.OBJECTIVE_OBJECT:
                obj_list.append({
                    "object": self.objectives[ordinal]["object"],
                    "number": self.objectives[ordinal]["number"]
                })
        if obj_list:
            owner.remove_objects(obj_list)

    def at_objective(self, type, object_key, number=1):
        """
        Called when the owner may complete some objectives.
        
        Args:
            type: objective's type defined in defines.py
            object_key: (string) the key of the relative object
            number: (int) the number of the object
        
        Returns:
            if the quest status has changed.
        """
        if type not in self.not_accomplished:
            return False

        status_changed = False
        index = 0

        # search all object objectives
        while index < len(self.not_accomplished[type]):
            ordinal = self.not_accomplished[type][index]
            index += 1

            if self.objectives[ordinal]["object"] == object_key:
                # if this object matches an objective
                status_changed = True

                # add accomplished number
                accomplished = self.db.accomplished.get(ordinal, 0)
                accomplished += number
                self.db.accomplished[ordinal] = accomplished

                if self.db.accomplished[ordinal] >= self.objectives[ordinal][
                        "number"]:
                    # if this objectives is accomplished, remove it
                    index -= 1
                    del (self.not_accomplished[type][index])

                    if not self.not_accomplished[type]:
                        # if all objectives are accomplished
                        del (self.not_accomplished[type])
                        break

        return status_changed
Example #26
0
def build_object(obj_key, level=None, caller=None, reset_location=True):
    """
    Build objects of a model.

    Args:
        obj_key: (string) The key of the object.
        level: (number) The object's level.
        caller: (command caller) If provide, running messages will send to the caller.
    """

    # Get object's information
    record = None
    typeclass_path = None
    try:
        model_name = TYPECLASS("OBJECT").model_name

        try:
            # Get record.
            record = WorldData.get_table_data(model_name, key=obj_key)
            record = record[0]
        except Exception as e:
            ostring = "Can not get record %s in %s: %s." % (obj_key,
                                                            model_name, e)
            print(ostring)
            print(traceback.print_exc())

        # get typeclass model
        typeclass_path = TYPECLASS_SET.get_module(record.typeclass)
    except Exception as e:
        ostring = "Can not get typeclass of %s: %s." % (obj_key, e)
        print(ostring)
        print(traceback.print_exc())
        pass

    if not record or not typeclass_path:
        ostring = "Can not find the data of %s." % obj_key
        print(ostring)
        print(traceback.print_exc())
        if caller:
            caller.msg(ostring)
        return

    # Create object.
    try:
        name = getattr(record, "name", "")
        obj = create.create_object(typeclass_path, name)
    except Exception as e:
        ostring = "Can not create obj %s: %s" % (obj_key, e)
        print(ostring)
        print(traceback.print_exc())
        if caller:
            caller.msg(ostring)
        return

    try:
        # Set data info.
        obj.set_data_key(record.key, level, reset_location=reset_location)
        obj.after_creation()
    except Exception as e:
        ostring = "Can not set data info to obj %s: %s" % (obj_key, e)
        print(ostring)
        print(traceback.print_exc())
        if caller:
            caller.msg(ostring)
        return

    return obj
Example #27
0
class MudderyWorldObject(TYPECLASS("OBJECT")):
    typeclass_key = "WORLD_OBJECT"
    typeclass_name = _("World Object", "typeclasses")
    model_name = "world_objects"
Example #28
0
class MudderyShopGoods(TYPECLASS("OBJECT")):
    """
    This is a shop goods. Shops show these objects to players. It contains a common object
    to sell and additional shop information.
    """
    typeclass_key = "SHOP_GOODS"
    typeclass_name = _("Goods", "typeclasses")
    model_name = "shop_goods"

    def at_object_creation(self):
        """
        Called once, when this object is first created. This is the
        normal hook to overload for most object types.

        """
        super(MudderyShopGoods, self).at_object_creation()

        self.available = False

    def after_data_loaded(self):
        """
        Load goods data.

        Returns:
            None
        """
        self.available = False

        self.shop_key = getattr(self.system, "shop", "")
        self.goods_key = getattr(self.system, "goods", "")
        self.goods_level = getattr(self.system, "level", 0)

        # set goods information
        self.price = getattr(self.system, "price", 0)
        self.unit_key = getattr(self.system, "unit", "")
        self.number = getattr(self.system, "number", 0)
        self.condition = getattr(self.system, "condition", "")

        # get price unit information
        try:
            # Get record.
            obj_model_name = TYPECLASS("OBJECT").model_name
            unit_record = WorldData.get_table_data(obj_model_name,
                                                   key=self.unit_key)
            unit_record = unit_record[0]
        except Exception as e:
            logger.log_errmsg("Can not find %s's price unit %s." %
                              (self.goods_key, self.unit_key))
            return

        self.unit_name = unit_record.name

        # load goods
        try:
            obj_record = WorldData.get_table_data(obj_model_name,
                                                  key=self.goods_key)
            obj_record = obj_record[0]
            goods_models = TYPECLASS_SET.get_class_modeles(
                obj_record.typeclass)
            goods_data = WorldData.get_tables_data(goods_models,
                                                   key=self.goods_key)
        except Exception as e:
            logger.log_errmsg("Can not find goods %s." % self.goods_key)
            return

        self.name = goods_data["name"]
        self.desc = goods_data["desc"]
        self.icon = goods_data.get("icon", None)

        self.available = True

    def sell_to(self, caller):
        """
        Buy this goods.

        Args:
            caller: the buyer

        Returns:

        """
        # check price
        unit_number = caller.get_object_number(self.unit_key)
        if unit_number < self.price:
            caller.msg(
                {"alert": _("Sorry, %s is not enough.") % self.unit_name})
            return

        # check if can get these objects
        if not caller.can_get_object(self.goods_key, self.number):
            caller.msg(
                {"alert": _("Sorry, you can not take more %s.") % self.name})
            return

        # Reduce price units.
        if not caller.remove_object(self.unit_key, self.price):
            caller.msg(
                {"alert": _("Sorry, %s is not enough.") % self.unit_name})
            return

        # Give goods.
        obj_list = [{"object": self.goods_key, "number": self.number}]
        caller.receive_objects(obj_list)
Example #29
0
def build_unique_objects(objects_data, type_name, caller=None):
    """
    Build all objects in a model.

    Args:
        model_name: (string) The name of the data model.
        caller: (command caller) If provide, running messages will send to the caller.
    """
    # new objects
    new_obj_keys = set(record.key for record in objects_data)

    # current objects
    current_objs = utils.search_obj_unique_type(type_name)

    # remove objects
    count_remove = 0
    count_update = 0
    count_create = 0
    current_obj_keys = set()

    for obj in current_objs:
        obj_key = obj.get_data_key()

        if obj_key in current_obj_keys:
            # This object is duplcated.
            ostring = "Deleting %s" % obj_key
            print(ostring)
            if caller:
                caller.msg(ostring)

            # If default home will be removed, set default home to the Limbo.
            if obj.dbref == settings.DEFAULT_HOME:
                settings.DEFAULT_HOME = "#2"
            obj.delete()
            count_remove += 1
            continue

        if not obj_key in new_obj_keys:
            # This object should be removed
            ostring = "Deleting %s" % obj_key
            print(ostring)
            if caller:
                caller.msg(ostring)

            # If default home will be removed, set default home to the Limbo.
            if obj.dbref == settings.DEFAULT_HOME:
                settings.DEFAULT_HOME = "#2"
            obj.delete()
            count_remove += 1
            continue

        try:
            # set data
            obj.load_data()
            # put obj to its default location
            obj.reset_location()
        except Exception as e:
            ostring = "%s can not load data:%s" % (obj.dbref, e)
            print(ostring)
            print(traceback.print_exc())
            if caller:
                caller.msg(ostring)

        current_obj_keys.add(obj_key)

    # Create new objects.
    object_model_name = TYPECLASS("OBJECT").model_name
    for record in objects_data:
        if not record.key in current_obj_keys:
            # Create new objects.
            ostring = "Creating %s." % record.key
            print(ostring)
            if caller:
                caller.msg(ostring)

            try:
                object_record = WorldData.get_table_data(object_model_name,
                                                         key=record.key)
                object_record = object_record[0]
                typeclass_path = TYPECLASS_SET.get_module(
                    object_record.typeclass)
                obj = create.create_object(typeclass_path, object_record.name)
                count_create += 1
            except Exception as e:
                ostring = "Can not create obj %s: %s" % (record.key, e)
                print(ostring)
                print(traceback.print_exc())
                if caller:
                    caller.msg(ostring)
                continue

            try:
                obj.set_data_key(record.key)
                obj.after_creation()
                utils.set_obj_unique_type(obj, type_name)
            except Exception as e:
                ostring = "Can not set data info to obj %s: %s" % (record.key,
                                                                   e)
                print(ostring)
                print(traceback.print_exc())
                if caller:
                    caller.msg(ostring)
                continue

    ostring = "Removed %d object(s). Created %d object(s). Updated %d object(s). Total %d objects.\n"\
              % (count_remove, count_create, count_update, len(objects_data))
    print(ostring)
    if caller:
        caller.msg(ostring)
Example #30
0
    def return_objectives(self):
        """
        Get the information of all objectives.
        Set desc to an objective can hide the details of the objective.
        """
        output = []

        for ordinal, objective in self.objectives.items():
            desc = objective["desc"]
            if desc:
                # If an objective has desc, use its desc.
                output.append({"ordinal": ordinal, "desc": objective["desc"]})
            else:
                # Or make a desc by other data.
                obj_num = objective["number"]
                accomplished = self.db.accomplished.get(ordinal, 0)

                if objective["type"] == defines.OBJECTIVE_TALK:
                    # talking
                    target = _("Talk to")
                    name = DIALOGUE_HANDLER.get_npc_name(objective["object"])

                    output.append({
                        "ordinal": ordinal,
                        "target": target,
                        "object": name,
                        "accomplished": accomplished,
                        "total": obj_num,
                    })

                elif objective["type"] == defines.OBJECTIVE_OBJECT:
                    # getting
                    target = _("Get")

                    # Get the name of the objective object.
                    object_key = objective["object"]
                    model_name = TYPECLASS("OBJECT").model_name

                    # Get record.
                    try:
                        record = WorldData.get_table_data(model_name,
                                                          key=object_key)
                        record = record[0]
                        name = record.name
                    except Exception as e:
                        logger.log_err("Can not find the quest object: %s" %
                                       object_key)
                        continue

                    output.append({
                        "ordinal": ordinal,
                        "target": target,
                        "object": name,
                        "accomplished": accomplished,
                        "total": obj_num,
                    })

                elif self.objectives[ordinal][
                        "type"] == defines.OBJECTIVE_KILL:
                    # getting
                    target = _("Kill")

                    # Get the name of the objective character.
                    object_key = self.objectives[ordinal]["object"]
                    model_name = TYPECLASS("OBJECT").model_name

                    # Get record.
                    try:
                        record = WorldData.get_table_data(model_name,
                                                          key=object_key)
                        record = record[0]
                        name = record.name
                    except Exception as e:
                        logger.log_err("Can not find the quest object: %s" %
                                       object_key)
                        continue

                    output.append({
                        "ordinal": ordinal,
                        "target": target,
                        "object": name,
                        "accomplished": accomplished,
                        "total": obj_num,
                    })

        return output