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