def load(self): from tuxemon.core import prepare self.dpad["surface"] = graphics.load_and_scale("gfx/d-pad.png") self.dpad["position"] = (0, prepare.SCREEN_SIZE[1] - self.dpad["surface"].get_height()) # Create the collision rectangle objects for the dpad so we can see if we're pressing a button self.dpad["rect"] = {} self.dpad["rect"]["up"] = Rect( self.dpad["position"][0] + (self.dpad["surface"].get_width() / 3), self.dpad["position"][1], # Rectangle position_y self.dpad["surface"].get_width() / 3, # Rectangle size_x self.dpad["surface"].get_height() / 2) # Rectangle size_y self.dpad["rect"]["down"] = Rect( self.dpad["position"][0] + (self.dpad["surface"].get_width() / 3), self.dpad["position"][1] + (self.dpad["surface"].get_height() / 2), self.dpad["surface"].get_width() / 3, self.dpad["surface"].get_height() / 2) self.dpad["rect"]["left"] = Rect( self.dpad["position"][0], self.dpad["position"][1] + (self.dpad["surface"].get_height() / 3), self.dpad["surface"].get_width() / 2, self.dpad["surface"].get_height() / 3) self.dpad["rect"]["right"] = Rect( self.dpad["position"][0] + (self.dpad["surface"].get_width() / 2), self.dpad["position"][1] + (self.dpad["surface"].get_height() / 3), self.dpad["surface"].get_width() / 2, self.dpad["surface"].get_height() / 3) # Create the buttons self.a_button = {} self.a_button["surface"] = graphics.load_and_scale("gfx/a-button.png") self.a_button["position"] = ( prepare.SCREEN_SIZE[0] - int(self.a_button["surface"].get_width() * 1.0), (self.dpad["position"][1] + (self.dpad["surface"].get_height() / 2) - (self.a_button["surface"].get_height() / 2))) self.a_button["rect"] = Rect(self.a_button["position"][0], self.a_button["position"][1], self.a_button["surface"].get_width(), self.a_button["surface"].get_height()) self.b_button = {} self.b_button["surface"] = graphics.load_and_scale("gfx/b-button.png") self.b_button["position"] = ( prepare.SCREEN_SIZE[0] - int(self.b_button["surface"].get_width() * 2.1), (self.dpad["position"][1] + (self.dpad["surface"].get_height() / 2) - (self.b_button["surface"].get_height() / 2))) self.b_button["rect"] = Rect(self.b_button["position"][0], self.b_button["position"][1], self.b_button["surface"].get_width(), self.b_button["surface"].get_height())
def __init__(self, **kwargs): self.tray = kwargs['tray'] self.monster = kwargs['monster'] self.sprite = kwargs['sprite'] self.state = kwargs['state'] self.empty = graphics.load_and_scale( 'gfx/ui/combat/empty_slot_icon.png') self.faint = graphics.load_and_scale( 'gfx/ui/icons/party/party_icon03.png') self.alive = graphics.load_and_scale( 'gfx/ui/icons/party/party_icon01.png') self.effected = graphics.load_and_scale( 'gfx/ui/icons/party/party_icon02.png') super().__init__()
def __init__(self, images, position, animation_speed=0.2, animation_loop=False): # Check to see what kind of image(s) are being loaded. images_type = type(images).__name__ # Handle loading a single image, multiple images, or surfaces if images_type == 'str' or images_type == 'unicode': surface = graphics.load_and_scale(images) self.images = [(surface, animation_speed)] elif images_type == 'list' or images_type == 'tuple': self.images = [] for item in images: item_type = type(item).__name__ if item_type == 'str' or item_type == 'unicode': surface = graphics.load_and_scale(images) else: surface = item self.images.append((surface, animation_speed)) else: surface = images self.images = [(surface, animation_speed)] # Create a pyganimation object using our loaded images. self.animation = pyganim.PygAnimation(self.images, loop=animation_loop) self.animation.play() self.animation.pause() self.rect = self.images[0][0].get_rect(topleft=position) self.visible = True self.state = "" self.moving = False self.move_destination = (0, 0) self.move_delta = [0, 0] self.move_duration = 0. self.move_time = 0. self.fading = False self.fade_duration = 0. self.shaking = False
def startup(self, **kwargs): super(MonsterMenuState, self).startup(**kwargs) # make a text area to show messages self.text_area = TextArea(self.font, self.font_color, (96, 96, 96)) self.text_area.rect = Rect(tools.scale_sequence([20, 80, 80, 100])) self.sprites.add(self.text_area, layer=100) # Set up the border images used for the monster slots self.monster_slot_border = {} self.monster_portrait = pygame.sprite.Sprite() self.hp_bar = HpBar() self.exp_bar = ExpBar() # load and scale the monster slot borders root = "gfx/ui/monster/" border_types = ["empty", "filled", "active"] for border_type in border_types: filename = root + border_type + "_monster_slot_border.png" border = graphics.load_and_scale(filename) filename = root + border_type + "_monster_slot_bg.png" background = graphics.load_image(filename) window = GraphicBox(border, background, None) self.monster_slot_border[border_type] = window # TODO: something better than this global, load_sprites stuff for monster in local_session.player.monsters: monster.load_sprites()
def draw_monster_info(self, surface, monster, rect): # position and draw hp bar hp_rect = rect.copy() left = rect.width * .6 right = rect.right - tools.scale(4) hp_rect.width = right - left hp_rect.left = left hp_rect.height = tools.scale(8) hp_rect.centery = rect.centery # draw the hp bar self.hp_bar.value = monster.current_hp / monster.hp self.hp_bar.draw(surface, hp_rect) # draw the name text_rect = rect.inflate(-tools.scale(6), -tools.scale(6)) draw_text(surface, monster.name, text_rect, font=self.font) # draw the level info text_rect.top = rect.bottom - tools.scale(7) draw_text(surface, " Lv " + str(monster.level), text_rect, font=self.font) # draw any status icons # TODO: caching or something, idk # TODO: not hardcode icon sizes for index, status in enumerate(monster.status): if status.icon: image = graphics.load_and_scale(status.icon) pos = (rect.width * .4) + (index * tools.scale(32)), rect.y + tools.scale(5) surface.blit(image, pos)
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 startup(self, *args, **kwargs): super().startup(*args, **kwargs) # used to determine how player can target techniques self.user = kwargs.get("user") self.action = kwargs.get("action") self.player = kwargs.get("player") # load and scale the menu borders border = graphics.load_and_scale(self.borders_filename) self.border = GraphicBox(border, None, None)
def load_sprites(self): """Loads the monster's sprite images as Pygame surfaces. :rtype: Boolean :returns: True if the sprites are already loaded. **Examples:** >>> bulbatux.load_sprites() >>> bulbatux.sprites """ if len(self.sprites): return True self.sprites["front"] = graphics.load_and_scale( self.front_battle_sprite) self.sprites["back"] = graphics.load_and_scale(self.back_battle_sprite) self.sprites["menu"] = graphics.load_and_scale(self.menu_sprite_1) return False
def load_graphics(self): """ Loads all the graphical elements of the menu Will load some elements from disk, so needs to be called at least once. """ if not self.transparent: # load and scale the _background background = None if self.background_filename: background = graphics.load_image(self.background_filename) # load and scale the menu borders border = None if self.draw_borders: border = graphics.load_and_scale(self.borders_filename) # set the helper to draw the _background self.window = GraphicBox(border, background, self.background_color) # handle the arrow cursor image = graphics.load_and_scale(self.cursor_filename) self.arrow = MenuCursor(image)
def load_sprites(self): """ Load sprite graphics :return: """ # TODO: refactor animations into renderer # Get all of the player's standing animation images. self.standing = {} for standing_type in facing: filename = "{}_{}.png".format(self.sprite_name, standing_type) path = os.path.join("sprites", filename) self.standing[standing_type] = load_and_scale(path) self.playerWidth, self.playerHeight = self.standing["front"].get_size( ) # The player's sprite size in pixels # avoid cutoff frames when steps don't line up with tile movement frames = 3 frame_duration = (1000 / CONFIG.player_walkrate) / frames / 1000 * 2 # Load all of the player's sprite animations anim_types = ['front_walk', 'back_walk', 'left_walk', 'right_walk'] for anim_type in anim_types: images = [ 'sprites/{}_{}.{}.png'.format(self.sprite_name, anim_type, str(num).rjust(3, '0')) for num in range(4) ] frames = [] for image in images: surface = load_and_scale(image) frames.append((surface, frame_duration)) self.sprite[anim_type] = pyganim.PygAnimation(frames, loop=True) # Have the animation objects managed by a conductor. # With the conductor, we can call play() and stop() on all the animation objects # at the same time, so that way they'll always be in sync with each other. self.moveConductor.add(self.sprite)
def show_combat_dialog(self): """ Create and show the area where battle messages are displayed """ # make the border and area at the bottom of the screen for messages x, y, w, h = self.client.screen.get_rect() rect = Rect(0, 0, w, h // 4) rect.bottomright = w, h border = graphics.load_and_scale(self.borders_filename) self.dialog_box = GraphicBox(border, None, self.background_color) self.dialog_box.rect = rect self.sprites.add(self.dialog_box, layer=100) # make a text area to show messages self.text_area = TextArea(self.font, self.font_color) self.text_area.rect = self.dialog_box.calc_inner_rect(self.dialog_box.rect) self.sprites.add(self.text_area, layer=100)
def load_technique_animation(technique): """ Return animated sprite from a technique :param tuxemon.core.technique.Technique technique: :rtype: tuxemon.core.sprite.Sprite """ if not technique.images: return None frame_time = .09 images = list() for fn in technique.images: image = graphics.load_and_scale(fn) images.append((image, frame_time)) tech = PygAnimation(images, False) sprite = Sprite() sprite.image = tech sprite.rect = tech.get_rect() return sprite
def load_technique_animation(technique): """ TODO: move to some generic animation loading thingy :param technique: :rtype: tuxemon.core.sprite.Sprite """ frame_time = .09 images = list() for fn in technique.images: image = graphics.load_and_scale(fn) images.append((image, frame_time)) tech = PygAnimation(images, False) sprite = Sprite() sprite.image = tech sprite.rect = tech.get_rect() return sprite
def animate_capture_monster(self, is_captured, num_shakes, monster): """ Animation for capturing monsters. :param is_captured: boolean representing success of capture :param num_shakes: number of shakes before animation ends :param monster: the monster :return: """ monster_sprite = self._monster_sprite_map.get(monster, None) capdev = self.load_sprite('gfx/items/capture_device.png') animate = partial(self.animate, capdev.rect, transition='in_quad', duration=1.0) graphics.scale_sprite(capdev, .4) capdev.rect.center = scale(0), scale(0) animate(x=monster_sprite.rect.centerx) animate(y=monster_sprite.rect.centery) self.task(partial(toggle_visible, monster_sprite), 1.0) # make the monster go away temporarily def kill(): self._monster_sprite_map[monster].kill() self.hud[monster].kill() del self._monster_sprite_map[monster] del self.hud[monster] # TODO: cache this sprite from the first time it's used. # also, should loading animated sprites be more convenient? images = list() for fn in ["capture%02d.png" % i for i in range(1, 10)]: fn = 'animations/technique/' + fn image = graphics.load_and_scale(fn) images.append((image, .07)) tech = PygAnimation(images, False) sprite = Sprite() sprite.image = tech sprite.rect = tech.get_rect() self.task(tech.play, 1.0) self.task(partial(self.sprites.add, sprite), 1.0) sprite.rect.midbottom = monster_sprite.rect.midbottom def shake_ball(initial_delay): animate = partial(self.animate, duration=0.1, transition='linear', delay=initial_delay) animate(capdev.rect, y=scale(3), relative=True) animate = partial(self.animate, duration=0.2, transition='linear', delay=initial_delay + 0.1) animate(capdev.rect, y=-scale(6), relative=True) animate = partial(self.animate, duration=0.1, transition='linear', delay=initial_delay + 0.3) animate(capdev.rect, y=scale(3), relative=True) for i in range(0, num_shakes): shake_ball(1.8 + i * 1.0) # leave a 0.6s wait between each shake if is_captured: self.task(kill, 2 + num_shakes) else: breakout_delay = 1.8 + num_shakes * 1.0 self.task(partial(toggle_visible, monster_sprite), breakout_delay) # make the monster appear again! self.task( audio.load_sound(monster.combat_call).play, breakout_delay) self.task(tech.play, breakout_delay) self.task(capdev.kill, breakout_delay)
def animate_monster_release(self, npc, monster): """ :type npc: tuxemon.core.npc.Npc :type monster: tuxemon.core.monster.Monster :return: """ feet = list(self._layout[npc]['home'][0].center) feet[1] += tools.scale(11) capdev = self.load_sprite('gfx/items/capture_device.png') graphics.scale_sprite(capdev, .4) capdev.rect.center = feet[0], feet[1] - scale(60) # animate the capdev falling fall_time = .7 animate = partial(self.animate, duration=fall_time, transition='out_quad') animate(capdev.rect, bottom=feet[1], transition='in_back') animate(capdev, rotation=720, initial=0) # animate the capdev fading away delay = fall_time + .6 fade_duration = .9 h = capdev.rect.height animate = partial(self.animate, duration=fade_duration, delay=delay) animate(capdev, width=1, height=h * 1.5) animate(capdev.rect, y=-scale(14), relative=True) # convert the capdev sprite so we can fade it easily def func(): capdev.image = graphics.convert_alpha_to_colorkey(capdev.image) self.animate(capdev.image, set_alpha=0, initial=255, duration=fade_duration) self.task(func, delay) self.task(capdev.kill, fall_time + delay + fade_duration) # load monster and set in final position monster_sprite = monster.get_sprite( "back" if npc.isplayer else "front", midbottom=feet) self.sprites.add(monster_sprite) self._monster_sprite_map[monster] = monster_sprite # position monster_sprite off screen and set animation to move it back to final spot monster_sprite.rect.top = self.client.screen.get_height() self.animate(monster_sprite.rect, bottom=feet[1], transition='out_back', duration=.9, delay=fall_time + .5) # capdev opening animation images = list() for fn in ["capture%02d.png" % i for i in range(1, 10)]: fn = 'animations/technique/' + fn image = graphics.load_and_scale(fn) images.append((image, .07)) delay = 1.3 tech = PygAnimation(images, False) sprite = Sprite() sprite.image = tech sprite.rect = tech.get_rect() sprite.rect.midbottom = feet self.task(tech.play, delay) self.task(partial(self.sprites.add, sprite), delay) # attempt to load and queue up combat_call call_sound = audio.load_sound(monster.combat_call) if call_sound: self.task(call_sound.play, delay) # update tuxemon balls to reflect fainted tuxemon for player, layout in self._layout.items(): self.animate_update_party_hud(player, layout['party'][0])
def load_graphics(self): """ Image become class attribute, so is shared. Eventually, implement some game-wide image caching """ image = graphics.load_and_scale(self.border_filename) ExpBar.border = GraphicBox(image)