def add_monster_into_play(self, player, monster): """ :param player: :param monster: :return: """ # TODO: refactor some into the combat animations self.animate_monster_release(player, monster) self.build_hud(self._layout[player]['hud'][0], monster) self.monsters_in_play[player].append(monster) # TODO: not hardcode if player is self.players[0]: self.alert( T.format('combat_call_tuxemon', {"name": monster.name.upper()})) elif self.is_trainer_battle: self.alert( T.format('combat_opponent_call_tuxemon', { "name": monster.name.upper(), "user": player.name.upper(), })) else: self.alert( T.format('combat_wild_appeared', {"name": monster.name.upper()}))
def add(menuitem): monster = menuitem.game_object if monster.current_hp == 0: tools.open_dialog(local_session, [T.format("combat_fainted", parameters={"name": monster.name})]) elif monster in self.active_monsters: tools.open_dialog(local_session, [T.format("combat_isactive", parameters={"name": monster.name})]) msg = T.translate("combat_replacement_is_fainted") tools.open_dialog(local_session, [msg]) else: self.add_monster_into_play(player, monster) self.client.pop_state()
def swap_it(menuitem): monster = menuitem.game_object if monster in self.client.get_state_by_name('CombatState').active_monsters: tools.open_dialog(local_session, [T.format('combat_isactive', {"name": monster.name})]) return elif monster.current_hp < 1: tools.open_dialog(local_session, [T.format('combat_fainted', {"name": monster.name})]) return combat_state = self.client.get_state_by_name("CombatState") swap = Technique("swap") swap.combat_state = combat_state player = local_session.player target = monster combat_state.enqueue_action(player, swap, target) self.client.pop_state() # close technique menu self.client.pop_state() # close the monster action menu
def on_menu_selection(self, menu_item): """ Called when player has selected something from the inventory Currently, opens a new menu depending on the state context :param menu_item: :return: """ item = menu_item.game_object state = self.determine_state_called_from() if not any(menu_item.game_object.validate(m) for m in local_session.player.monsters): msg = T.format('item_no_available_target', {'name': item.name}) tools.open_dialog(local_session, [msg]) elif state not in item.usable_in: msg = T.format('item_cannot_use_here', {'name': item.name}) tools.open_dialog(local_session, [msg]) else: self.open_confirm_use_menu(item)
def choose_target(menu_item): # open menu to choose target of technique technique = menu_item.game_object if technique.next_use > 0: params = {"move": technique.name, "name": self.monster.name} tools.open_dialog(local_session, [T.format('combat_recharging', params)]) return combat_state = self.client.get_state_by_name("CombatState") state = self.client.push_state("CombatTargetMenuState", player=combat_state.players[0], user=self.monster, action=technique) state.on_menu_selection = partial(enqueue_technique, technique)
def animate_party_status(self): """ Animate monsters that need to be fainted * Animation to remove monster is handled here TODO: check for faint status, not HP :rtype: None """ for player, party in self.monsters_in_play.items(): for monster in party: if fainted(monster): self.alert(T.format('combat_fainted', {"name": monster.name})) self.animate_monster_faint(monster) self.suppress_phase_change(3)
def enqueue_item(item, menu_item): target = menu_item.game_object # is the item valid to use? if not item.validate(target): msg = T.format('cannot_use_item_monster', {'name': item.name}) tools.open_dialog(local_session, [msg]) return # enqueue the item combat_state = self.client.get_state_by_name("CombatState") # TODO: don't hardcode to player0 combat_state.enqueue_action(combat_state.players[0], item, target) # close all the open menus self.client.pop_state() # close target chooser self.client.pop_state() # close the monster action menu
def show_monster_action_menu(self, monster): """ Show the main window for choosing player actions :param monster: Monster to choose an action for :type monster: tuxemon.core.monster.Monster :returns: None """ message = T.format('combat_monster_choice', {"name": monster.name}) self.alert(message) x, y, w, h = self.client.screen.get_rect() rect = Rect(0, 0, w // 2.5, h // 4) rect.bottomright = w, h state = self.client.push_state("MainCombatMenuState", columns=2) state.monster = monster state.rect = rect
def animate_parties_in(self): # TODO: break out functions here for each left_trainer, right_trainer = self.players right_monster = right_trainer.monsters[0] surface = pygame.display.get_surface() x, y, w, h = surface.get_rect() # TODO: not hardcode this player, opponent = self.players player_home = self._layout[player]['home'][0] opp_home = self._layout[opponent]['home'][0] y_mod = scale(50) duration = 3 back_island = self.load_sprite('gfx/ui/combat/' + self.graphics['island_back'], bottom=opp_home.bottom + y_mod, right=0) if self.is_trainer_battle: enemy = self.load_sprite( 'gfx/sprites/player/' + opponent.sprite_name + '_front.png', bottom=back_island.rect.bottom - scale(12), centerx=back_island.rect.centerx) self._monster_sprite_map[opponent] = enemy else: enemy = right_monster.get_sprite("front", bottom=back_island.rect.bottom - scale(12), centerx=back_island.rect.centerx) self._monster_sprite_map[right_monster] = enemy self.monsters_in_play[opponent].append(right_monster) self.sprites.add(enemy) self.build_hud(self._layout[opponent]['hud'][0], right_monster) if self.is_trainer_battle: self.alert( T.format('combat_trainer_appeared', {"name": opponent.name.upper()})) else: self.alert( T.format('combat_wild_appeared', {"name": right_monster.name.upper()})) front_island = self.load_sprite('gfx/ui/combat/' + self.graphics['island_front'], bottom=player_home.bottom - y_mod, left=w) trainer1 = self.load_sprite( 'gfx/sprites/player/' + player.sprite_name + '_back.png', bottom=front_island.rect.centery + scale(6), centerx=front_island.rect.centerx) self._monster_sprite_map[left_trainer] = trainer1 def flip(): enemy.image = pygame.transform.flip(enemy.image, 1, 0) trainer1.image = pygame.transform.flip(trainer1.image, 1, 0) flip() # flip images to opposite self.task(flip, 1.5) # flip the images to proper direction if not self.is_trainer_battle: # the combat call is handled by fill_battlefield_positions for trainer battles self.task(audio.load_sound(right_monster.combat_call).play, 1.5) # play combat call when it turns back animate = partial(self.animate, transition='out_quad', duration=duration) # top trainer animate(enemy.rect, back_island.rect, centerx=opp_home.centerx) animate(enemy.rect, back_island.rect, y=-y_mod, transition='out_back', relative=True) # bottom trainer animate(trainer1.rect, front_island.rect, centerx=player_home.centerx) animate(trainer1.rect, front_island.rect, y=y_mod, transition='out_back', relative=True)
def perform_action(self, user, technique, target=None): """ Do something with the thing: animated :param user: :param technique: Not a dict: a Technique or Item :param target: :returns: """ technique.advance_round() # This is the time, in seconds, that the animation takes to finish. action_time = 3.0 result = technique.use(user, target) if technique.use_item: # "Monster used move!" context = { "user": getattr(user, "name", ''), "name": technique.name, "target": target.name } message = T.format(technique.use_item, context) else: message = '' try: audio.load_sound(technique.sfx).play() except AttributeError: pass # action is performed, so now use sprites to animate it # this value will be None if the target is off screen target_sprite = self._monster_sprite_map.get(target, None) # slightly delay the monster shake, so technique animation # is synchronized with the damage shake motion hit_delay = 0 if user: # TODO: a real check or some params to test if should tackle, etc if result["should_tackle"]: hit_delay += .5 user_sprite = self._monster_sprite_map[user] self.animate_sprite_tackle(user_sprite) if target_sprite: self.task( partial(self.animate_sprite_take_damage, target_sprite), hit_delay + .2) self.task(partial(self.blink, target_sprite), hit_delay + .6) # TODO: track total damage # Track damage self._damage_map[target].add(user) element_damage_key = MULT_MAP.get(result['element_multiplier']) if element_damage_key: m = T.translate(element_damage_key) message += "\n" + m for status in result.get("statuses", []): m = T.format( status.use_item, { "name": technique.name, "user": status.link.name if status.link else "", "target": status.carrier.name }) message += "\n" + m else: # assume this was an item used # handle the capture device if result["capture"]: message += "\n" + T.translate('attempting_capture') action_time = result["num_shakes"] + 1.8 self.animate_capture_monster(result["success"], result["num_shakes"], target) # TODO: Don't end combat right away; only works with SP, and 1 member parties # end combat right here if result["success"]: self.task(self.end_combat, action_time + 0.5) # Display 'Gotcha!' first. self.task(partial(self.alert, T.translate('gotcha')), action_time) self._animation_in_progress = True return # generic handling of anything else else: msg_type = 'use_success' if result[ 'success'] else 'use_failure' template = getattr(technique, msg_type) if template: message += "\n" + T.translate(template) self.alert(message) self.suppress_phase_change(action_time) else: if result["success"]: self.suppress_phase_change() self.alert( T.format('combat_status_damage', { "name": target.name, "status": technique.name })) if result["success"] and target_sprite and technique.images: tech_sprite = self.get_technique_animation(technique) tech_sprite.rect.center = target_sprite.rect.center self.task(tech_sprite.image.play, hit_delay) self.task(partial(self.sprites.add, tech_sprite, layer=50), hit_delay) self.task(tech_sprite.kill, 3)