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

4from typing import Any, Type 

5 

6# -- third party -- 

7# -- own -- 

8from thb.actions import Damage, DrawCardStage, DrawCards, DropCards, FinalizeStage, ForEach 

9from thb.actions import LaunchCard, ShowCards, UserAction, migrate_cards, random_choose_card, ttags 

10from thb.actions import user_choose_cards, user_choose_players 

11from thb.cards.base import Card, Skill, VirtualCard 

12from thb.cards.classes import AttackCard, DuelCard, TreatAs, t_None 

13from thb.characters.base import Character, register_character_to 

14from thb.inputlets import ChooseOptionInputlet, ChoosePeerCardInputlet 

15from thb.mode import THBEventHandler 

16 

17 

18# -- code -- 

19class KanakoFaithCheers(UserAction): 

20 def apply_action(self): 

21 return self.game.process_action(DrawCards(self.target, 1)) 

22 

23 

24class KanakoFaithAttack(TreatAs, VirtualCard): 

25 treat_as = AttackCard 

26 

27 

28class KanakoFaithDuel(TreatAs, VirtualCard): 

29 treat_as = DuelCard 

30 

31 

32class KanakoFaithCounteract(UserAction): 

33 def apply_action(self): 

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

35 g = self.game 

36 src.dead or tgt.dead or g.process_action(KanakoFaithCounteractPart1(src, tgt)) 

37 src.dead or tgt.dead or g.process_action(KanakoFaithCounteractPart2(src, tgt)) 

38 return True 

39 

40 

41class KanakoFaithCounteractPart1(UserAction): 

42 

43 def apply_action(self): 

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

45 g = self.game 

46 

47 catnames = ('cards', 'showncards', 'equips') 

48 cats = [getattr(tgt, i) for i in catnames] 

49 

50 card = g.user_input([src], ChoosePeerCardInputlet(self, tgt, catnames)) 

51 card = card or random_choose_card(g, cats) 

52 

53 assert card 

54 self.card = card 

55 

56 g.players.reveal(card) 

57 g.process_action(DropCards(src, tgt, [card])) 

58 return True 

59 

60 

61class KanakoFaithCounteractPart2(UserAction): 

62 def apply_action(self): 

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

64 g = self.game 

65 

66 choice = g.user_input([tgt], ChooseOptionInputlet(self, ('duel', 'attack'))) 

67 

68 cls: Type[Any] 

69 if choice == 'duel': 

70 cls = KanakoFaithDuel 

71 elif choice == 'attack': 

72 cls = KanakoFaithAttack 

73 else: 

74 cls = KanakoFaithAttack 

75 

76 g.process_action(LaunchCard(tgt, [src], cls(tgt), bypass_check=True)) 

77 

78 return True 

79 

80 

81class KanakoFaithEffect(UserAction): 

82 card_usage = 'drop' 

83 

84 def apply_action(self): 

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

86 g = self.game 

87 

88 has_card = src.cards or src.showncards or src.equips 

89 

90 if has_card and g.user_input([tgt], ChooseOptionInputlet(self, ('drop', 'draw'))) == 'drop': 

91 g.process_action(KanakoFaithCounteract(tgt, src)) 

92 else: 

93 g.process_action(KanakoFaithCheers(tgt, src)) 

94 

95 return True 

96 

97 

98class KanakoFaithAction(ForEach): 

99 action_cls = KanakoFaithEffect 

100 

101 def prepare(self): 

102 self.source.tags['kanako_faith'] = True 

103 

104 def is_valid(self): 

105 return not self.source.tags['kanako_faith'] 

106 

107 

108class KanakoFaith(Skill): 

109 associated_action = KanakoFaithAction 

110 skill_category = ['character', 'active', 'once'] 

111 

112 def check(self): 

113 return not self.associated_cards 

114 

115 def target(self, p, tl): 

116 g = self.game 

117 l = g.players.rotate_to(p) 

118 del l[0] 

119 

120 dists = LaunchCard.calc_raw_distance(g, p, AttackCard()) 

121 return ([t for t in l if not t.dead and dists[t] <= 1], True) 

122 

123 

124class VirtueAction(UserAction): 

125 card_usage = 'handover' 

126 

127 def apply_action(self): 

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

129 g = self.game 

130 g.process_action(DrawCards(tgt, 2)) 

131 

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

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

134 

135 if not c: return False 135 ↛ exitline 135 didn't return from function 'apply_action', because the return on line 135 wasn't executed

136 

137 g.players.reveal(c) 

138 g.process_action(ShowCards(tgt, [c])) 

139 migrate_cards([c], src.cards) 

140 

141 if c.suit == Card.HEART: 

142 g.process_action(DrawCards(src, 1)) 

143 

144 self.card = c 

145 

146 return True 

147 

148 def cond(self, cl): 

149 return len(cl) == 1 and not cl[0].is_card(VirtualCard) 

150 

151 

152class VirtueHandler(THBEventHandler): 

153 interested = ['action_before'] 

154 

155 def handle(self, evt_type, act): 

156 if evt_type == 'action_before' and isinstance(act, DrawCardStage): 

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

158 return act 

159 

160 tgt = act.target 

161 if not tgt.has_skill(Virtue): 

162 return act 

163 

164 g = self.game 

165 pl = [p for p in g.players if not p.dead and p is not tgt] 

166 pl = pl and user_choose_players(self, tgt, pl) 

167 if not pl: 

168 return act 

169 

170 act.cancelled = True 

171 g.process_action(VirtueAction(tgt, pl[0])) 

172 

173 return act 

174 

175 def choose_player_target(self, tl): 

176 if not tl: 176 ↛ 177line 176 didn't jump to line 177, because the condition on line 176 was never true

177 return (tl, False) 

178 

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

180 

181 

182class KanakoFaithKOF(Skill): 

183 associated_action = None 

184 skill_category = ['character', 'passive', 'compulsory'] 

185 target = t_None() 

186 

187 

188class KanakoFaithKOFAction(DrawCards): 

189 pass 

190 

191 

192class KanakoFaithKOFHandler(THBEventHandler): 

193 interested = ['action_before', 'action_apply'] 

194 

195 def handle(self, evt_type, act): 

196 if evt_type == 'action_before' and isinstance(act, FinalizeStage): 

197 tgt = act.target 

198 if not tgt.has_skill(KanakoFaithKOF): 

199 return act 

200 

201 g = self.game 

202 op = g.get_opponent(tgt) 

203 

204 if tgt.life > op.life or ttags(tgt)['kanako_faith_kof']: 

205 n = tgt.life - (len(tgt.cards) + len(tgt.showncards)) 

206 if n > 0: 

207 g.process_action(KanakoFaithKOFAction(tgt, n)) 

208 

209 elif evt_type == 'action_apply' and isinstance(act, Damage): 

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

211 g = self.game 

212 

213 if src and src.has_skill(KanakoFaithKOF) and tgt is g.get_opponent(src): 

214 ttags(src)['kanako_faith_kof'] = True 

215 

216 return act 

217 

218 

219class Virtue(Skill): 

220 associated_action = None 

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

222 target = t_None() 

223 

224 

225@register_character_to('common', '-kof') 

226class Kanako(Character): 

227 skills = [Virtue, KanakoFaith] 

228 eventhandlers = [VirtueHandler] 

229 maxlife = 4 

230 

231 

232# @register_character_to('kof') 

233class KanakoKOF(Character): 

234 skills = [KanakoFaithKOF] 

235 eventhandlers = [KanakoFaithKOFHandler] 

236 maxlife = 4