Hide keyboard shortcuts

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 -*- 

2 

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 

13 

14 

15# -- code -- 

16class Echo(Skill): 

17 associated_action = None 

18 skill_category = ['character', 'passive'] 

19 target = t_None() 

20 

21 

22class EchoAction(UserAction): 

23 def __init__(self, source, target, card): 

24 self.source, self.target, self.card = source, target, card 

25 

26 def apply_action(self): 

27 src, tgt, c = self.target, self.target, self.card 

28 g = self.game 

29 

30 assert c.detached 

31 

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 

38 

39 migrate_cards([c], tgt.cards, unwrap=True) 

40 

41 return True 

42 

43 

44class EchoHandler(THBEventHandler): 

45 interested = ['action_after'] 

46 execute_after = [ 

47 'DyingHandler', 

48 'AyaRoundfanHandler', 

49 'NenshaPhoneHandler', 

50 ] 

51 

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 

57 

58 if not tgt.has_skill(Echo): 

59 return act 

60 

61 g = self.game 

62 pact = g.action_stack[-1] 

63 card = getattr(pact, 'associated_card', None) 

64 if not card: 

65 return act 

66 

67 if not card.detached or card.unwrapped: 

68 return act 

69 

70 if not VirtualCard.unwrap([card]): 

71 return act 

72 

73 if not g.user_input([tgt], ChooseOptionInputlet(self, (False, True))): 

74 return act 

75 

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 

79 

80 g.process_action(EchoAction(tgt, p, card)) 

81 

82 return act 

83 

84 def choose_player_target(self, tl): 

85 if not tl: 

86 return (tl, False) 

87 

88 return (tl[-1:], True) 

89 

90 

91class Resonance(Skill): 

92 associated_action = None 

93 skill_category = ['character', 'passive'] 

94 target = t_None() 

95 

96 

97class ResonanceDrawAction(DrawCards): 

98 pass 

99 

100 

101class ResonanceLaunchCard(LaunchCard): 

102 pass 

103 

104 

105class ResonanceAction(AskForCard): 

106 card_usage = 'launch' 

107 

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 

113 

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 

118 

119 def ask_for_action_verify(self, p, cl, tl): 

120 return ResonanceLaunchCard(self.target, [self.victim], cl[0], bypass_check=True).can_fire() 

121 

122 

123class ResonanceHandler(THBEventHandler): 

124 interested = ['action_done'] 

125 

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 

130 

131 if act.cancelled or src.dead or tgt.dead: 

132 return act 

133 

134 if not src.has_skill(Resonance): 

135 return act 

136 

137 g = self.game 

138 pl = [p for p in g.players if not p.dead and p not in (src, tgt)] 

139 

140 if not pl: 

141 return act 

142 

143 pl = user_choose_players(self, src, pl) 

144 

145 if not pl: 

146 return act 

147 

148 g.process_action(ResonanceAction(src, pl[0], tgt)) 

149 

150 return act 

151 

152 def choose_player_target(self, tl): 

153 if not tl: 

154 return (tl, False) 

155 

156 return (tl[-1:], True) 

157 

158 

159@register_character_to('common') 

160class Kyouko(Character): 

161 skills = [Echo, Resonance] 

162 eventhandlers = [EchoHandler, ResonanceHandler] 

163 maxlife = 4