Exemplo n.º 1
0
class MudderyMonster(get_class("CLASS_BASE_CHARACTER")):
    """
    Default mob. Monsters are hostile to players, they can be attacked.
    """
    def after_data_loaded(self):
        """
        Init the character.
        """
        super(MudderyMonster, self).after_data_loaded()

        # Character can auto fight.
        self.auto_fight = True

        # set home
        self.home = self.location

        # load dialogues.
        self.load_dialogues()

    def load_dialogues(self):
        """
        Load dialogues.
        """
        npc_key = self.get_data_key()
        dialogues = DATA_SETS.npc_dialogues.objects.filter(npc=npc_key)

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

    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
                })

            commands.append({
                "name": _("Attack"),
                "cmd": "attack",
                "args": self.dbref
            })
        return commands
Exemplo n.º 2
0
class MudderyRoom(get_class("CLASS_BASE_OBJECT"), DefaultRoom):
    """
    Rooms are like any Object, except their location is None
    (which is default). They also use basetype_setup() to
    add locks so they cannot be puppeted or picked up.
    (to change that, use at_object_creation instead)

    See examples/object.py for a list of
    properties and methods available on all Objects.
    """
    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(MudderyRoom, self).at_object_creation()

        self.peaceful = False
        self.position = None
        self.background = None

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

        self.peaceful = getattr(self.dfield, "peaceful", False)

        self.position = None
        try:
            # set position
            position = getattr(self.dfield, "position", None)
            if position:
                self.position = ast.literal_eval(position)
        except Exception, e:
            logger.log_tracemsg("load position error: %s" % e)

        # get background
        self.background = None
        resource_key = getattr(self.dfield, "background", None)
        if resource_key:
            try:
                resource_info = DATA_SETS.image_resources.objects.get(
                    key=resource_key)
                self.background = {
                    "name": resource_info.resource,
                    "width": resource_info.image_width,
                    "height": resource_info.image_height
                }
            except Exception, e:
                logger.log_tracemsg("Load background %s error: %s" %
                                    (resource_key, e))
Exemplo n.º 3
0
class MudderyArea(get_class("CLASS_BASE_OBJECT")):
    """
    Areas are compose the whole map. Rooms are belongs to 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
        self.background_point = None
        self.corresp_map_pos = None

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

        # get background
        self.background = None
        resource_key = getattr(self.dfield, "background", None)
        if resource_key:
            try:
                resource_info = DATA_SETS.image_resources.objects.get(
                    key=resource_key)
                self.background = {
                    "name": resource_info.resource,
                    "width": resource_info.image_width,
                    "height": resource_info.image_height
                }
            except Exception, e:
                logger.log_tracemsg("Load background %s error: %s" %
                                    (resource_key, e))

        self.background_point = None
        try:
            # set background point
            background_point = getattr(self.dfield, "background_point", None)
            if background_point:
                self.background_point = ast.literal_eval(background_point)
        except Exception, e:
            logger.log_tracemsg("load background point '%s' error: %s" %
                                (background_point, e))
Exemplo n.º 4
0
class MudderyObjectCreator(get_class("CLASS_BASE_OBJECT")):
    """
    This object loads attributes from world data on init automatically.
    """

    # initialize loot handler in a lazy fashion
    @lazy_property
    def loot_handler(self):
        return LootHandler(self, DATA_SETS.creator_loot_list.model)

    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.dfield, "loot_verb", None)
        if not self.loot_verb:
            self.loot_verb = _("Loot")
        self.loot_condition = getattr(self.dfield, "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)
Exemplo n.º 5
0
class MudderyCommonObject(get_class("CLASS_BASE_OBJECT")):
    """
    This is a common object. Players can put it in their inventories.
    
    There can be a lot of common objects of the same kind in the game, so their haven't
    home and fixed locations.
    
    It has two additional properties: max_stack(int) and unique(bool). They decied the number
    of the object that a player can put in his inventory.
    """
    def at_object_creation(self):
        """
        Set default values.
        """
        super(MudderyCommonObject, self).at_object_creation()

        # set default number
        if not self.attributes.has("number"):
            self.db.number = 0

    def after_data_loaded(self):
        """
        Initial this object.
        """
        super(MudderyCommonObject, self).after_data_loaded()

        # set object stack info
        self.max_stack = getattr(self.dfield, "max_stack", 1)
        self.unique = getattr(self.dfield, "unique", False)
        self.can_remove = getattr(self.dfield, "can_remove", True)
        self.can_discard = getattr(self.dfield, "can_discard", True)

    def get_number(self):
        """
        Get object's number.
        """
        return self.db.number

    def increase_num(self, number):
        """
        Increase object's number.
        """
        if number == 0:
            return

        if number < 0:
            raise MudderyError("%s can not increase a negative nubmer." %
                               self.get_data_key())

        if self.max_stack == 1 and self.db.number == 1:
            raise MudderyError("%s can not stack." % self.get_data_key())

        if self.db.number + number > self.max_stack:
            raise MudderyError("%s over stack." % self.get_data_key())

        self.db.number += number
        return

    def decrease_num(self, number):
        """
        Decrease object's number.
        """
        if number == 0:
            return

        if number < 0:
            raise MudderyError("%s can not decrease a negative nubmer." %
                               self.get_data_key())

        if self.db.number < number:
            raise MudderyError("%s's number will below zero." %
                               self.get_data_key())

        self.db.number -= number
        return

    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:
            if self.location and self.can_discard:
                commands.append({
                    "name": _("Discard"),
                    "cmd": "discard",
                    "args": self.dbref
                })
        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
        """
        return _("No effect."), 0
Exemplo n.º 6
0
class MudderyNPC(get_class("CLASS_BASE_CHARACTER")):
    """
    Default NPC. NPCs are friendly to players, they can not be attacked.
    """
    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(MudderyNPC, 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(MudderyNPC, self).after_data_loaded()

        # set level
        self.db.level = getattr(self.dfield, "level", 1)

        # 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.
        """
        npc_key = self.get_data_key()
        dialogues = DATA_SETS.npc_dialogues.objects.filter(npc=npc_key)

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

    def load_shops(self):
        """
        Load character's shop.
        """
        # shops records
        shop_records = DATA_SETS.npc_shops.objects.filter(
            npc=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

    def get_available_commands(self, caller):
        """
        This returns a list of available commands.
        """
        commands = []
        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
            })

        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)
Exemplo n.º 7
0
class MudderyCharacter(get_class("CLASS_BASE_OBJECT"), DefaultCharacter):
    """
    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

    """
    # initialize loot handler in a lazy fashion
    @lazy_property
    def loot_handler(self):
        return LootHandler(self, DATA_SETS.character_loot_list.model)

    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(MudderyCharacter, self).at_object_creation()

        # set default values
        if not self.attributes.has("level"):
            self.db.level = 1
        if not self.attributes.has("exp"):
            self.db.exp = 0
        if not self.attributes.has("hp"):
            self.db.hp = 1
        if not self.attributes.has("team"):
            self.db.team = 0

        # init equipments
        if not self.attributes.has("equipments"):
            self.db.equipments = {}
        if not self.attributes.has("position_names"):
            self.db.position_names = {}
        self.reset_equip_positions()

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

        # set quests
        if not self.attributes.has("completed_quests"):
            self.db.completed_quests = set()
        if not self.attributes.has("current_quests"):
            self.db.current_quests = {}
        
        # skill's gcd
        self.skill_gcd = GAME_SETTINGS.get("global_cd")
        self.auto_cast_skill_cd = GAME_SETTINGS.get("auto_cast_skill_cd")
        self.gcd_finish_time = 0
        
        # loop for auto cast skills
        self.auto_cast_loop = None
        
        self.target = None
        self.reborn_time = 0
        
        # A temporary character will be deleted after the combat finished.
        self.is_temp = False


    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(MudderyCharacter, self).at_object_delete()
        if not result:
            return result
            
        # leave combat
        if self.ndb.combat_handler:
            self.ndb.combat_handler.remove_character(self)
        
        # stop auto casting
        self.stop_auto_combat_skill()
        
        # delete all skills
        for skill in self.db.skills.values():
            skill.delete()

        # delete all contents
        for content in self.contents:
            content.delete()
        
        return True
                            
    def after_data_loaded(self):
        """
        Init the character.
        """
        super(MudderyCharacter, self).after_data_loaded()
        
        # skill's ai
        ai_choose_skill_class = class_from_module(settings.AI_CHOOSE_SKILL)
        self.ai_choose_skill = ai_choose_skill_class()

        # skill's gcd
        self.skill_gcd = GAME_SETTINGS.get("global_cd")
        self.auto_cast_skill_cd = GAME_SETTINGS.get("auto_cast_skill_cd")
        self.gcd_finish_time = 0
        
        # loop for auto cast skills
        self.auto_cast_loop = None

        # clear target
        self.target = None

        # set reborn time
        self.reborn_time = getattr(self.dfield, "reborn_time", 0)

        # A temporary character will be deleted after the combat finished.
        self.is_temp = False

        # update equipment positions
        self.reset_equip_positions()

        # load default skills
        self.load_default_skills()

        # load default objects
        self.load_default_objects()

        # refresh data
        self.refresh_data()
        
    def after_data_key_changed(self):
        """
        Called at data_key changed.
        """
        super(MudderyCharacter, self).after_data_key_changed()

        # reset hp
        self.db.hp = self.max_hp

    def reset_equip_positions(self):
        """
        Reset equipment's position data.
        Returns:
            None
        """
        positions = []
        self.db.position_names = {}

        # reset equipment's position
        for record in DATA_SETS.equipment_positions.objects.all():
            positions.append(record.key)
            self.db.position_names[record.key] = record.name

        for position in self.db.equipments:
            if position not in positions:
                del self.db.equipments[position]

        for position in positions:
            if position not in self.db.equipments:
                self.db.equipments[position] = None

        # reset equipments status
        equipped = set()
        equipments = self.db.equipments
        for position in equipments:
            if equipments[position]:
                equipped.add(equipments[position])

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

    def set_level(self, level):
        """
        Set character's level.
        Args:
            level: character's new level

        Returns:
            None
        """
        if self.db.level == level:
            return

        self.db.level = level
        self.refresh_data()

    def refresh_data(self):
        """
        Refresh character's data, calculate character's attributes.
        """
        # load level data
        self.load_model_data()
        self.load_custom_attributes(CHARACTER_ATTRIBUTES_INFO)
        
        # load equips
        self.ues_equipments()

        # load passive skills
        self.cast_passive_skills()

    def get_appearance(self, caller):
        """
        This is a convenient hook for a 'look'
        command to call.
        """
        # get name, description and available commands.
        info = super(MudderyCharacter, self).get_appearance(caller)
        info["max_hp"] = self.max_hp
        info["hp"] = self.db.hp

        return info

    def change_status(self, increments):
        """
        Change the value of specified status.
        
        Args:
            increments: (dict) values to change.
            
        Return:
            (dict) values that actrually changed.
        """
        changes = {}
        for key in increments:
            changes[key] = 0

            if self.attributes.has(key):
                # try to add to self's db
                target = self.db
            elif hasattr(self, key):
                # try to add to self's attribute
                target = self
            elif self.custom_attributes_handler.has(key):
                # try to add to self's cattr
                target = self.cattr
            else:
                # no target
                continue

            origin_value = getattr(target, key)
            increment = increments[key]
            
            # check limits
            max_key = "max_" + key
            max_source = None
            if self.attributes.has(max_key):
                # try to add to self's db
                max_source = self.db
            elif hasattr(self, max_key):
                # try to add to self's attribute
                max_source = self
            elif self.custom_attributes_handler.has(max_key):
                # try to add to self's cattr
                max_source = self.cattr

            if max_source is not None:
                max_value = getattr(max_source, max_key)
                if origin_value + increment > max_value:
                    increment = max_value - origin_value
            
            min_value = 0
            min_key = "min_" + key
            min_source = None
            if self.attributes.has(min_key):
                # try to add to self's db
                min_source = self.db
            elif hasattr(self, min_key):
                # try to add to self's attribute
                min_source = self
            elif self.custom_attributes_handler.has(min_key):
                # try to add to self's cattr
                min_source = self.cattr

            if min_source is not None:
                min_value = getattr(min_source, min_key)

            if origin_value + increment < min_value:
                increment = min_value - origin_value

            # set value
            if increment != 0:
                setattr(target, key, origin_value + increment)
                changes[key] = increment
            
        return changes
        
    def get_combat_status(self):
        """
        Get character status used in combats.
        """
        return {"max_hp": self.max_hp,
                "hp": self.db.hp}

    def load_model_data(self):
        """
        Load character's level data.
        """
        model_name = getattr(self.dfield, "model", None)
        if not model_name:
            model_name = self.get_data_key()

        try:
            # get data from db
            model_data = DATA_SETS.character_models.objects.get(key=model_name, level=self.db.level)

            reserved_fields = {"id", "key", "name", "level"}
            for field in model_data._meta.fields:
                if field.name in reserved_fields:
                    continue
                setattr(self.dfield, field.name, model_data.serializable_value(field.name))
        except Exception, e:
            logger.log_errmsg("Can't load character %s's level info (%s, %s): %s" %
                              (self.get_data_key(), model_name, self.db.level, e))

        self.max_exp = getattr(self.dfield, "max_exp", 0)
        self.max_hp = getattr(self.dfield, "max_hp", 1)
        self.give_exp = getattr(self.dfield, "give_exp", 0)
Exemplo n.º 8
0
class MudderyExit(get_class("CLASS_BASE_OBJECT"), DefaultExit):
    """
    Exits are connectors between rooms. Exits are normal Objects except
    they defines the `destination` property. It also does work in the
    following methods:

     basetype_setup() - sets default exit locks (to change, use `at_object_creation` instead).
     at_cmdset_get(**kwargs) - this is called when the cmdset is accessed and should
                              rebuild the Exit cmdset along with a command matching the name
                              of the Exit object. Conventionally, a kwarg `force_init`
                              should force a rebuild of the cmdset, this is triggered
                              by the `@alias` command when aliases are changed.
     at_failed_traverse() - gives a default error message ("You cannot
                            go there") if exit traversal fails and an
                            attribute `err_traverse` is not defined.

    Relevant hooks to overload (compared to other types of Objects):
        at_before_traverse(traveller) - called just before traversing.
        at_after_traverse(traveller, source_loc) - called just after traversing.
        at_failed_traverse(traveller) - called if traversal failed for some reason. Will
                                        not be called if the attribute `err_traverse` is
                                        defined, in which case that will simply be echoed.
    """
    def after_data_loaded(self):
        """
        Load exit data.

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

        # set exit's destination
        self.set_obj_destination(getattr(self.dfield, "destination", None))

        # set action verb
        self.verb = getattr(self.dfield, "verb", _("GOTO"))

    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.

        """
        # trigger event
        if traversing_object.has_account:
            return self.event.at_character_traverse(traversing_object)

        return True

    def at_failed_traverse(self, traversing_object, **kwargs):
        """
        Overloads the default hook to implement a simple default error message.

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

        Notes:
            Using the default exits, this hook will not be called if an
            Attribute `err_traverse` is defined - this will in that case be
            read for an error string instead.

        """
        traversing_object.msg({"alert": "You cannot go there."})

    def get_name(self):
        """
        Get exit's name.
        """
        if self.name:
            return self.name
        elif self.destination:
            return self.destination.get_name()
        else:
            return ""

    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 = [{"name": self.verb, "cmd": "goto", "args": self.dbref}]
        return commands
Exemplo n.º 9
0
class MudderySkill(get_class("CLASS_BASE_OBJECT")):
    """
    A skill of the character.
    """
    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()

        # set status
        if not self.attributes.has("owner"):
            self.db.owner = 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 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.dfield, "function", "")
        self.cd = getattr(self.dfield, "cd", 0)
        self.passive = getattr(self.dfield, "passive", False)
        self.main_type = getattr(self.dfield, "main_type", "")
        self.sub_type = getattr(self.dfield, "sub_type", "")

        message_model = getattr(self.dfield, "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.db.owner = owner

        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, passive):
        """
        Cast this skill.

        Args:
            target: (object) skill's target.
            passive: (boolean) cast a passive skill.

        Returns:
            (result, cd):
                result: (dict) skill's result
                cd: (dict) skill's cd
        """
        owner = self.db.owner

        not_available = self.check_available(passive)
        if not_available:
            message = {"cast": not_available}
        else:
            results = self.do_skill(target)

            message = {
                "caller": owner.dbref,
                "skill": self.get_data_key(),
                "cast": self.cast_message(target)
            }

            if target:
                message["target"] = target.dbref

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

            # set status
            status = {}
            if owner.is_in_combat():
                for char in owner.ndb.combat_handler.get_all_characters():
                    status[char.dbref] = char.get_combat_status()
            elif owner.location:
                status[owner.dbref] = owner.get_combat_status()
            message["status"] = status

        # send message
        if owner.is_in_combat():
            owner.ndb.combat_handler.msg_all({"skill_cast": message})
        elif owner.location:
            owner.location.msg_contents({"skill_cast": message})

        return True

    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.db.owner, target)

    def check_available(self, passive):
        """
        Check this skill.
        
        Args:
            passive: (boolean) cast a passive skill.

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

        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.db.owner:
            caller_name = self.db.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
Exemplo n.º 10
0
class MudderyShopGoods(get_class("CLASS_BASE_OBJECT")):
    """
    This is a shop goods. Shops show these objects to players. It contains a common object
    to sell and additional shop information.
    """
    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()

        # Set default values.
        if not self.attributes.has("goods"):
            self.db.goods = None

        self.available = False

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

        Returns:
            None
        """
        self.available = False

        self.shop_key = getattr(self.dfield, "shop", "")
        self.goods_key = getattr(self.dfield, "goods", "")

        if not self.shop_key or not self.goods_key:
            if self.db.goods:
                self.db.goods.delete()
                self.db.goods = None
            return

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

        # get price unit information
        unit_record = get_object_record(self.unit_key)
        if not unit_record:
            logger.log_errmsg("Can not find %s price unit %s." %
                              (self.goods_key, self.unit_key))
            return
        self.unit_name = unit_record.name

        # load goods object
        goods = self.db.goods
        if goods:
            if goods.get_data_key() == self.goods_key:
                goods.load_data()
            else:
                goods.set_data_key(self.goods_key)
        else:
            goods = build_object(self.goods_key)
            if goods:
                self.db.goods = goods
            else:
                logger.log_err("Can not create goods %s." % self.goods_key)
                return

        self.name = goods.get_name()
        self.desc = goods.db.desc
        self.icon = getattr(goods, "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.db.goods.get_data_key(),
                                     self.number):
            caller.msg({
                "alert":
                _("Sorry, you can not take more %s.") %
                self.db.goods.get_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.db.goods.get_data_key(),
            "number": self.number
        }]
        caller.receive_objects(obj_list)
Exemplo n.º 11
0
class MudderyQuest(get_class("CLASS_BASE_OBJECT")):
    """
    This class controls quest's objectives. Hooks are called when a character doing some things.
    """

    # initialize loot handler in a lazy fashion
    @lazy_property
    def loot_handler(self):
        return LootHandler(self, DATA_SETS.quest_reward_list.model)

    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 = DATA_SETS.quest_objectives.objects.filter(quest=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_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.
        """
        objectives = []
        for ordinal in self.objectives:
            desc = self.objectives[ordinal]["desc"]
            if desc:
                # If an objective has desc, use its desc.
                objectives.append({"desc": self.objectives[ordinal]["desc"]})
            else:
                # Or make a desc by other data.
                obj_num = self.objectives[ordinal]["number"]
                accomplished = self.db.accomplished.get(ordinal, 0)

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

                    objectives.append({
                        "target": target,
                        "object": name,
                        "accomplished": accomplished,
                        "total": obj_num,
                    })
                elif self.objectives[ordinal][
                        "type"] == defines.OBJECTIVE_OBJECT:
                    # getting
                    target = _("Get")
                    name = ""

                    # Get the name of the objective object.
                    object_key = self.objectives[ordinal]["object"]
                    model_names = OBJECT_KEY_HANDLER.get_models(object_key)
                    for model_name in model_names:
                        model = apps.get_model(settings.WORLD_DATA_APP,
                                               model_name)
                        # Get record.
                        try:
                            record = model.objects.get(key=object_key)
                            name = record.name
                            break
                        except Exception, e:
                            pass

                    objectives.append({
                        "target": target,
                        "object": name,
                        "accomplished": accomplished,
                        "total": obj_num,
                    })
                elif self.objectives[ordinal][
                        "type"] == defines.OBJECTIVE_KILL:
                    # getting
                    target = _("Kill")
                    name = ""

                    # Get the name of the objective character.
                    object_key = self.objectives[ordinal]["object"]
                    model_names = OBJECT_KEY_HANDLER.get_models(object_key)
                    for model_name in model_names:
                        model = apps.get_model(settings.WORLD_DATA_APP,
                                               model_name)
                        # Get record.
                        try:
                            record = model.objects.get(key=object_key)
                            name = record.name
                            break
                        except Exception, e:
                            pass

                    objectives.append({
                        "target": target,
                        "object": name,
                        "accomplished": accomplished,
                        "total": obj_num,
                    })
Exemplo n.º 12
0
class MudderyPlayerCharacter(get_class("CLASS_BASE_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

    """

    # 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()

        # honour
        if not HONOURS_MAPPER.has_info(self):
            if self.db.level >= settings.MIN_HONOUR_LEVEL:
                HONOURS_MAPPER.set_honour(self, 0)
            else:
                HONOURS_MAPPER.set_honour(self, -1)

        # 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 = {}

        # Choose a random career.
        if not self.attributes.has("career"):
            self.db.career = ""
            try:
                careers = DATA_SETS.character_careers.objects.all()
                if careers:
                    career = random.choice(careers)
                    self.db.career = career.key
            except Exception, e:
                pass
Exemplo n.º 13
0
class MudderyShop(get_class("CLASS_BASE_OBJECT")):
    """
    A shop.
    """
    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.dfield, "verb", None)

    def load_goods(self):
        """
        Load shop goods.
        """
        # shops records
        goods_records = DATA_SETS.shop_goods.objects.filter(
            shop=self.get_data_key())

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

        # search current goods
        current_goods = set()
        for item in self.contents:
            key = item.get_data_key()
            if key in goods_keys:
                current_goods.add(key)
            else:
                # remove goods that is not in goods_keys
                item.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

                goods_obj.move_to(self, quiet=True)

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

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

    def return_shop_info(self):
        """
        Get shop information.
        """
        info = {
            "dbref": self.dbref,
            "name": self.get_name(),
            "desc": self.db.desc,
            "icon": getattr(self, "icon", None)
        }

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

        return info

    def return_shop_goods(self):
        """
        Get shop's information.
        """
        goods_list = []

        # Get shop goods
        for item in self.contents:
            if not item.available:
                continue

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

            goods_list.append(goods)

        return goods_list