Coverage for thb/characters/kyouko.py : 96%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
3# -- stdlib --
4# -- third party --
5# -- own --
6from thb.actions import AskForCard, Damage, DrawCards, LaunchCard, UserAction, migrate_cards
7from thb.actions import user_choose_players
8from thb.cards.base import Skill, VirtualCard
9from thb.cards.classes import Attack, AttackCard, t_None
10from thb.characters.base import Character, register_character_to
11from thb.inputlets import ChooseOptionInputlet
12from thb.mode import THBEventHandler
15# -- code --
16class Echo(Skill):
17 associated_action = None
18 skill_category = ['character', 'passive']
19 target = t_None()
22class EchoAction(UserAction):
23 def __init__(self, source, target, card):
24 self.source, self.target, self.card = source, target, card
26 def apply_action(self):
27 src, tgt, c = self.target, self.target, self.card
28 g = self.game
30 assert c.detached
32 shadow = Echo(src)
33 for a in g.action_stack:
34 if isinstance(a, LaunchCard) and a.card is c:
35 a.card = shadow
36 elif getattr(a, 'associated_card', None) is c:
37 a.associated_card = shadow
39 migrate_cards([c], tgt.cards, unwrap=True)
41 return True
44class EchoHandler(THBEventHandler):
45 interested = ('action_after',)
46 execute_after = (
47 'DyingHandler',
48 'AyaRoundfanHandler',
49 'NenshaPhoneHandler',
50 )
52 def handle(self, evt_type, act):
53 if evt_type == 'action_after' and isinstance(act, Damage):
54 tgt = act.target
55 if tgt.dead:
56 return act
58 if not tgt.has_skill(Echo):
59 return act
61 g = self.game
62 pact = g.action_stack[-1]
63 card = getattr(pact, 'associated_card', None)
64 if not card:
65 return act
67 if not card.detached or card.unwrapped:
68 return act
70 if not VirtualCard.unwrap([card]):
71 return act
73 if not g.user_input([tgt], ChooseOptionInputlet(self, (False, True))):
74 return act
76 attack = card.is_card(AttackCard)
77 pl = attack and user_choose_players(self, tgt, [p for p in g.players if not p.dead])
78 p = pl[0] if pl else tgt
80 g.process_action(EchoAction(tgt, p, card))
82 return act
84 def choose_player_target(self, tl):
85 if not tl: 85 ↛ 86line 85 didn't jump to line 86, because the condition on line 85 was never true
86 return (tl, False)
88 return (tl[-1:], True)
91class Resonance(Skill):
92 associated_action = None
93 skill_category = ['character', 'passive']
94 target = t_None()
97class ResonanceDrawAction(DrawCards):
98 pass
101class ResonanceLaunchCard(LaunchCard):
102 pass
105class ResonanceAction(AskForCard):
106 card_usage = 'launch'
108 def __init__(self, source, target, victim):
109 AskForCard.__init__(self, source, target, AttackCard)
110 self.source = source
111 self.target = target
112 self.victim = victim
114 def process_card(self, c):
115 g = self.game
116 g.process_action(ResonanceLaunchCard(self.target, [self.victim], c, bypass_check=True))
117 return True
119 def ask_for_action_verify(self, p, cl, tl):
120 return ResonanceLaunchCard(self.target, [self.victim], cl[0], bypass_check=True).can_fire()
123class ResonanceHandler(THBEventHandler):
124 interested = ['action_done']
126 def handle(self, evt_type, act):
127 if evt_type == 'action_done' and isinstance(act, Attack):
128 src = act.source
129 tgt = act.target
131 if act.cancelled or src.dead or tgt.dead:
132 return act
134 if not src.has_skill(Resonance):
135 return act
137 g = self.game
138 pl = [p for p in g.players if not p.dead and p not in (src, tgt)]
140 if not pl:
141 return act
143 pl = user_choose_players(self, src, pl)
145 if not pl: 145 ↛ 146line 145 didn't jump to line 146, because the condition on line 145 was never true
146 return act
148 g.process_action(ResonanceAction(src, pl[0], tgt))
150 return act
152 def choose_player_target(self, tl):
153 if not tl: 153 ↛ 154line 153 didn't jump to line 154, because the condition on line 153 was never true
154 return (tl, False)
156 return (tl[-1:], True)
159@register_character_to('common')
160class Kyouko(Character):
161 skills = [Echo, Resonance]
162 eventhandlers = [EchoHandler, ResonanceHandler]
163 maxlife = 4