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 Damage, DropCards, GenericAction, LaunchCard, LifeLost, UserAction 

7from thb.actions import random_choose_card, ttags, user_choose_cards 

8from thb.cards.base import Skill, VirtualCard 

9from thb.cards.classes import AttackCard, DuelCard, t_None, t_OtherOne 

10from thb.characters.base import Character, register_character_to 

11from thb.inputlets import ChooseOptionInputlet, ChoosePeerCardInputlet 

12from thb.mode import THBEventHandler 

13 

14 

15# -- code -- 

16class CirnoDropCards(GenericAction): 

17 def __init__(self, source, target, cards): 

18 self.source = source 

19 self.target = target 

20 self.cards = cards 

21 

22 def apply_action(self): 

23 src, tgt = self.source, self.target 

24 cards = self.cards 

25 

26 g = self.game 

27 g.players.reveal(cards) 

28 g.process_action(DropCards(src, tgt, cards)) 

29 return True 

30 

31 

32class BakadesuAction(UserAction): 

33 card_usage = 'launch' 

34 

35 def apply_action(self): 

36 src, tgt = self.source, self.target 

37 ttags(src)['bakadesu'] = True 

38 

39 cl = user_choose_cards(self, tgt, ('cards', 'showncards')) 

40 g = self.game 

41 if cl: 41 ↛ 42line 41 didn't jump to line 42, because the condition on line 41 was never true

42 g.process_action(LaunchCard(tgt, [src], cl[0])) 

43 else: 

44 c = g.user_input([src], ChoosePeerCardInputlet(self, tgt, ('cards', 'showncards', 'equips'))) 

45 c = c or random_choose_card(g, [tgt.cards, tgt.showncards, tgt.equips]) 

46 c and g.process_action(CirnoDropCards(src, tgt, [c])) 

47 

48 return True 

49 

50 def is_valid(self): 

51 src, tgt = self.source, self.target 

52 if not LaunchCard(tgt, [src], AttackCard()).can_fire(): 

53 return False 

54 

55 return not ttags(src)['bakadesu'] 

56 

57 def cond(self, cl): 

58 if len(cl) != 1: 

59 return False 

60 c = cl[0] 

61 

62 return c.is_card(AttackCard) and ( 

63 c.resides_in is not None and c.resides_in.type in ('cards', 'showncards') 

64 ) 

65 

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

67 src, tgt = self.source, self.target 

68 return LaunchCard(tgt, [src], cl[0]).can_fire() 

69 

70 

71class Bakadesu(Skill): 

72 associated_action = BakadesuAction 

73 skill_category = ['character', 'active'] 

74 target = t_OtherOne() 

75 

76 def check(self): 

77 return not self.associated_cards 

78 

79 

80class PerfectFreeze(Skill): 

81 associated_action = None 

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

83 target = t_None() 

84 

85 

86class PerfectFreezeAction(UserAction): 

87 card_usage = 'drop' 

88 

89 def __init__(self, source, target, damage): 

90 self.source = source 

91 self.target = target 

92 self.damage = damage 

93 

94 def apply_action(self): 

95 self.damage.cancelled = True 

96 

97 src, tgt = self.source, self.target 

98 g = self.game 

99 cl = user_choose_cards(self, tgt, ('cards', 'showncards', 'equips')) 

100 c = cl[0] if cl else random_choose_card(g, [tgt.cards, tgt.showncards, tgt.equips]) 

101 

102 if c: 102 ↛ 109line 102 didn't jump to line 109, because the condition on line 102 was never false

103 damage = c.resides_in is not tgt.equips 

104 g.process_action(CirnoDropCards(src, tgt, [c])) 

105 

106 if damage: 

107 g.process_action(LifeLost(src, tgt, 1)) 

108 

109 return True 

110 

111 def cond(self, cl): 

112 if len(cl) != 1: 

113 return False 

114 

115 if cl[0].is_card(VirtualCard): 115 ↛ 118line 115 didn't jump to line 118, because the condition on line 115 was never false

116 return False 

117 

118 return True 

119 

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

121 return CirnoDropCards(self.source, self.target, cl).can_fire() 

122 

123 

124class PerfectFreezeHandler(THBEventHandler): 

125 interested = ['action_before'] 

126 

127 execute_after = [ 

128 'RepentanceStickHandler', 

129 'AyaRoundfanHandler', 

130 ] 

131 

132 def handle(self, evt_type, act): 

133 if evt_type == 'action_before' and isinstance(act, Damage): 

134 if act.cancelled: 134 ↛ 135line 134 didn't jump to line 135, because the condition on line 134 was never true

135 return act 

136 

137 src, tgt = act.source, act.target 

138 if not (src and src.has_skill(PerfectFreeze)): 

139 return act 

140 

141 g = self.game 

142 for lc in reversed(g.action_stack): 142 ↛ 146line 142 didn't jump to line 146, because the loop on line 142 didn't complete

143 if isinstance(lc, LaunchCard): 

144 break 

145 else: 

146 return act 

147 

148 if src is not lc.source: 148 ↛ 149line 148 didn't jump to line 149, because the condition on line 148 was never true

149 return act 

150 

151 c = lc.card 

152 if not c.is_card(AttackCard) and not c.is_card(DuelCard): 

153 return act 

154 

155 if not g.user_input([src], ChooseOptionInputlet(self, (False, True))): 

156 return act 

157 

158 g.process_action(PerfectFreezeAction(src, tgt, act)) 

159 

160 return act 

161 

162 

163@register_character_to('common') 

164class Cirno(Character): 

165 skills = [Bakadesu, PerfectFreeze] 

166 eventhandlers = [PerfectFreezeHandler] 

167 maxlife = 4