def start(self): player = self.session.player # Don't start a battle if we don't even have monsters in our party yet. if not check_battle_legal(player): logger.debug("battle is not legal, won't start") return False world = self.session.client.get_state_name("WorldState") if not world: return False npc = world.get_entity(self.parameters.npc_slug) npc.load_party() # Lookup the environment env_slug = "grass" if 'environment' in player.game_variables: env_slug = player.game_variables['environment'] env = db.lookup(env_slug, table="environment") # Add our players and setup combat logger.debug("Starting battle!") self.session.client.push_state("CombatState", players=(player, npc), combat_type="trainer", graphics=env['battle_graphics']) # Start some music! filename = env['battle_music'] self.session.client.event_engine.execute_action( "play_music", [filename])
def load(self, slug): """Loads and sets this technique's attributes from the technique database. The technique is looked up in the database by slug. :param slug: The slug of the technique to look up in the database. :type slug: String :rtype: None """ results = db.lookup(slug, table="technique") self.slug = results["slug"] # a short English identifier self.name = T.translate(self.slug) # locale-specific string self.sort = results['sort'] # technique use notifications (translated!) # NOTE: should be `self.use_tech`, but Technique and Item have overlapping checks self.use_item = T.maybe_translate(results.get("use_tech")) self.use_success = T.maybe_translate(results.get("use_success")) self.use_failure = T.maybe_translate(results.get("use_failure")) self.category = results["category"] self.icon = results["icon"] self._combat_counter = 0 self._life_counter = 0 if results.get('types'): self.type1 = results["types"][0] if len(results['types']) > 1: self.type2 = results["types"][1] else: self.type2 = None else: self.type1 = self.type2 = None self.power = results.get("power") self.is_fast = results.get("is_fast") self.recharge_length = results.get("recharge") self.is_area = results.get("is_area") self.range = results.get("range") self.accuracy = results.get("accuracy") self.potency = results.get("potency") self.effect = results["effects"] self.target = process_targets(results["target"]) # Load the animation sprites that will be used for this technique self.animation = results["animation"] if self.animation: self.images = [] animation_dir = prepare.fetch("animations", "technique") directory = sorted(os.listdir(animation_dir)) for image in directory: if self.animation and image.startswith(self.animation): self.images.append( os.path.join("animations/technique", image)) # Load the sound effect for this technique self.sfx = results["sfx"]
def load(self, slug): """Loads and sets this items's attributes from the item.db database. The item is looked up in the database by slug. :param slug: The item slug to look up in the monster.item database. :type slug: String :rtype: None :returns: None **Examples:** >>> potion = Item() >>> potion.load('potion') # Load an item by slug. >>> pprint.pprint(potion.__dict__) { 'description': u'Heals a monster by 50 HP.', 'effects': [u'heal'], 'slug': 'potion', 'name': u'potion', 'sprite': u'resources/gfx/items/potion.png', 'surface': <Surface(66x90x32 SW)>, 'surface_size_original': (66, 90), 'type': u'Consumable' } """ try: results = db.lookup(slug, table="item") except KeyError: logger.error(msg="Failed to find item with slug {}".format(slug)) return self.slug = results["slug"] # short English identifier self.name = T.translate(self.slug) # translated name self.description = T.translate("{}_description".format( self.slug)) # will be locale string # item use notifications (translated!) self.use_item = T.translate(results["use_item"]) self.use_success = T.translate(results["use_success"]) self.use_failure = T.translate(results["use_failure"]) # misc attributes (not translated!) self.sort = results['sort'] assert self.sort self.type = results["type"] self.sprite = results["sprite"] self.usable_in = results["usable_in"] self.target = process_targets(results["target"]) self.effects = self.parse_effects(results.get("effects", [])) self.conditions = self.parse_conditions(results.get("conditions", [])) self.surface = graphics.load_and_scale(self.sprite) self.surface_size_original = self.surface.get_size()
def set_flairs(self): """Sets the flairs of this monster if they were not already configured :rtype: None :returns: None """ if len(self.flairs) > 0 or self.slug == "": return results = db.lookup(self.slug, table="monster") flairs = results.get("flairs") if flairs: for flair in flairs: flair = Flair(flair['category'], random.choice(flair['names'])) self.flairs[flair.category] = flair
def start(self): player = self.session.player # Don't start a battle if we don't even have monsters in our party yet. if not check_battle_legal(player): return False slug = self.parameters.encounter_slug encounters = db.database['encounter'][slug]['monsters'] encounter = _choose_encounter(encounters, self.parameters.total_prob) # If a random encounter was successfully rolled, look up the monster and start the # battle. if encounter: logger.info("Starting random encounter!") npc = _create_monster_npc(encounter) # Lookup the environment env_slug = "grass" if 'environment' in player.game_variables: env_slug = player.game_variables['environment'] env = db.lookup(env_slug, table="environment") # Add our players and setup combat # "queueing" it will mean it starts after the top of the stack is popped (or replaced) self.session.client.queue_state("CombatState", players=(player, npc), combat_type="monster", graphics=env['battle_graphics']) # stop the player world = self.session.client.get_state_name("WorldState") world.lock_controls() world.stop_player() # flash the screen self.session.client.push_state("FlashTransition") # Start some music! filename = env['battle_music'] self.session.client.event_engine.execute_action( "play_music", [filename])
def __init__(self, npc_slug, sprite_name=None, combat_front=None, combat_back=None): super().__init__() # load initial data from the npc database npc_data = db.lookup(npc_slug, table="npc") self.slug = npc_slug # This is the NPC's name to be used in dialog self.name = T.translate(self.slug) # use 'animations' passed in # Hold on the the string so it can be sent over the network self.sprite_name = sprite_name self.combat_front = combat_front self.combat_back = combat_back if self.sprite_name is None: # Try to use the sprites defined in the JSON data self.sprite_name = npc_data["sprite_name"] if self.combat_front is None: self.combat_front = npc_data["combat_front"] if self.combat_back is None: self.combat_back = npc_data["combat_back"] # general self.behavior = "wander" # not used for now self.game_variables = {} # Tracks the game state self.interactions = [] # List of ways player can interact with the Npc self.isplayer = False # used for various tests, idk self.monsters = [ ] # This is a list of tuxemon the npc has. Do not modify directly self.inventory = {} # The Player's inventory. # Variables for long-term item and monster storage # Keeping these seperate so other code can safely # assume that all values are lists self.monster_boxes = dict() self.item_boxes = dict() # combat related self.ai = None # Whether or not this player has AI associated with it self.speed = 10 # To determine combat order (not related to movement!) self.moves = [] # list of techniques # pathfinding and waypoint related self.pathfinding = None self.path = [] self.final_move_dest = [ 0, 0 ] # Stores the final destination sent from a client # This is used to 'set back' when lost, and make movement robust. # If entity falls off of map due to a bug, it can be returned to this value. # When moving to a waypoint, this is used to detect if movement has overshot # the destination due to speed issues or framerate jitters. self.path_origin = None # movement related self.move_direction = None # Set this value to move the npc (see below) self.facing = "down" # Set this value to change the facing direction self.moverate = CONFIG.player_walkrate # walk by default self.ignore_collisions = False # What is "move_direction"? # Move direction allows other functions to move the npc in a controlled way. # To move the npc, change the value to one of four directions: left, right, up or down. # The npc will then move one tile in that direction until it is set to None. # TODO: move sprites into renderer so class can be used headless self.playerHeight = 0 self.playerWidth = 0 self.standing = {} # Standing animation frames self.sprite = {} # Moving animation frames self.moveConductor = pyganim.PygConductor() self.load_sprites() self.rect = Rect( self.tile_pos, (self.playerWidth, self.playerHeight)) # Collision rect
def load_from_db(self, slug): """Loads and sets this monster's attributes from the monster.db database. The monster is looked up in the database by name. :param slug: Slug to lookup :type slug: str :rtype: None """ # Look up the monster by name and set the attributes in this instance results = db.lookup(slug, table="monster") if results is None: logger.error("monster {} is not found".format(slug)) raise RuntimeError self.slug = results["slug"] # short English identifier self.name = T.translate(results["slug"]) # translated name self.description = T.translate("{}_description".format( results["slug"])) # translated description self.category = T.translate(results["category"]) # translated category self.shape = results.get("shape", "landrace").lower() types = results.get("types") if types: self.type1 = results["types"][0].lower() if len(types) > 1: self.type2 = results["types"][1].lower() self.weight = results['weight'] # Look up the moves that this monster can learn AND LEARN THEM. moveset = results.get("moveset") if moveset: for move in moveset: self.moveset.append(move) if move['level_learned'] >= self.level: technique = Technique(move['technique']) self.learn(technique) # Look up the evolutions for this monster. evolutions = results.get("evolutions") if evolutions: for evolution in evolutions: self.evolutions.append(evolution) # Look up the monster's sprite image paths self.front_battle_sprite = self.get_sprite_path( results['sprites']['battle1']) self.back_battle_sprite = self.get_sprite_path( results['sprites']['battle2']) self.menu_sprite_1 = self.get_sprite_path(results['sprites']['menu1']) self.menu_sprite_2 = self.get_sprite_path(results['sprites']['menu2']) # get sound slugs for this monster, defaulting to a generic type-based sound self.combat_call = results.get("sounds", {}).get( "combat_call", "sound_{}_call".format(self.type1)) self.faint_call = results.get("sounds", {}).get( "faint_call", "sound_{}_faint".format(self.type1)) # Load the monster AI # TODO: clean up AI 'core' loading and what not ai_result = results['ai'] if ai_result == "SimpleAI": self.ai = ai.SimpleAI() elif ai_result == "RandomAI": self.ai = ai.RandomAI()