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

2from __future__ import annotations 

3 

4# -- stdlib -- 

5# -- third party -- 

6# -- own -- 

7from game.base import ActionShootdown, InputTransaction 

8from thb.actions import ActionStage, ActionStageLaunchCard, DrawCards, DropCardStage, FinalizeStage 

9from thb.actions import GenericAction, LaunchCard, PlayerTurn, PrepareStage, ShowCards, UserAction 

10from thb.actions import ask_for_action 

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

12from thb.cards.classes import PhysicalCard, t_None, t_Self 

13from thb.characters.base import Character, register_character_to 

14from thb.inputlets import ChooseOptionInputlet 

15from thb.mode import THBEventHandler 

16 

17 

18# -- code -- 

19class WindWalkLaunch(ActionStageLaunchCard): 

20 pass 

21 

22 

23class WindWalkSkipAction(GenericAction): 

24 def apply_action(self) -> bool: 

25 g = self.game 

26 ActionStage.force_break(g) 

27 turn = PlayerTurn.get_current(g) 

28 try: 

29 turn.pending_stages.remove(DropCardStage) 

30 turn.pending_stages.remove(FinalizeStage) 

31 except Exception: 

32 pass 

33 

34 return True 

35 

36 

37class WindWalkAction(UserAction): 

38 card_usage = 'launch' 

39 

40 def apply_action(self): 

41 g = self.game 

42 tgt = self.target 

43 

44 while True: 

45 dc = DrawCards(tgt, 1) 

46 g.process_action(dc) 

47 c, = dc.cards 

48 self.card = c 

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

50 

51 with InputTransaction('ActionStageAction', [tgt]) as trans: 

52 p, rst = ask_for_action( 

53 self, [tgt], ('cards', 'showncards'), g.players, trans=trans 

54 ) 

55 

56 if p is not tgt: 

57 g.process_action(WindWalkSkipAction(tgt, tgt)) 

58 break 

59 

60 assert p 

61 assert rst 

62 

63 cl, tl = rst 

64 g.players.reveal(cl) 

65 c, = cl 

66 

67 g.process_action(WindWalkLaunch(p, tl, c)) 

68 

69 return True 

70 

71 def cond(self, cl): 

72 if not (cl and len(cl) == 1): 

73 return False 

74 

75 return bool(cl[0].associated_action) and [self.card] == VirtualCard.unwrap(cl) 

76 

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

78 assert len(cl) == 1 

79 return WindWalkLaunch(p, tl, cl[0]).can_fire() 

80 

81 def choose_player_target(self, tl): 

82 return tl, True 

83 

84 

85class WindWalkTargetLimit(ActionShootdown): 

86 pass 

87 

88 

89class WindWalkHandler(THBEventHandler): 

90 interested = ['action_apply', 'action_shootdown'] 

91 

92 def handle(self, evt_type, act): 

93 if evt_type == 'action_apply' and isinstance(act, LaunchCard): 

94 src = act.source 

95 if act.card.is_card(WindWalk): 

96 return act 

97 

98 if not src.has_skill(WindWalk): 

99 return act 

100 

101 src.tags['windwalk_last_targets'] = set(act.target_list) 

102 

103 elif evt_type == 'action_apply' and isinstance(act, PrepareStage): 

104 src = act.source 

105 if not src.has_skill(WindWalk): 

106 return act 

107 

108 src.tags['windwalk_last_targets'] = set() 

109 

110 elif evt_type == 'action_shootdown' and isinstance(act, LaunchCard): 

111 g = self.game 

112 if not isinstance(g.action_stack[-1], WindWalkAction): 

113 return act 

114 

115 src, tl = act.source, set(act.target_list) 

116 last_tl = src.tags['windwalk_last_targets'] or set() 

117 

118 if not tl <= last_tl: 

119 raise WindWalkTargetLimit 

120 

121 return act 

122 

123 return act 

124 

125 

126class WindWalk(Skill): 

127 associated_action = WindWalkAction 

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

129 target = t_Self() 

130 usage = 'drop' 

131 

132 def check(self): 

133 cl = self.associated_cards 

134 if not(cl and len(cl) == 1): 

135 return False 

136 

137 if cl[0].is_card(Skill): 

138 return False 

139 

140 return True 

141 

142 

143class Dominance(Skill): 

144 associated_action = None 

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

146 target = t_None() 

147 

148 

149class DominanceAction(PlayerTurn): 

150 pass 

151 

152 

153class DominanceHandler(THBEventHandler): 

154 interested = ['action_after', 'action_apply'] 

155 

156 def handle(self, evt_type, act): 

157 if evt_type == 'action_apply' and isinstance(act, PrepareStage): 

158 t = act.target.tags 

159 t['dominance_suits'] = set() 

160 t['dominance_suit_SPADE'] = False 

161 t['dominance_suit_CLUB'] = False 

162 t['dominance_suit_HEART'] = False 

163 t['dominance_suit_DIAMOND'] = False 

164 

165 elif evt_type == 'action_apply' and isinstance(act, LaunchCard): 

166 if not act.source.has_skill(Dominance): 

167 return act 

168 

169 card = act.card 

170 if not card.is_card(PhysicalCard): 

171 return act 

172 

173 suit = card.suit 

174 if suit not in (Card.SPADE, Card.CLUB, Card.HEART, Card.DIAMOND): 

175 return act 

176 

177 try: 

178 t = act.source.tags 

179 t['dominance_suits'].add(suit) 

180 t['dominance_suit_%s' % Card.SUIT_REV[suit]] = True 

181 

182 except AttributeError: 

183 pass 

184 

185 elif evt_type == 'action_after' and isinstance(act, FinalizeStage): 

186 tgt = act.target 

187 if not tgt.has_skill(Dominance): 

188 return act 

189 

190 if len(tgt.tags['dominance_suits'] or set()) != 4: 

191 return act 

192 

193 g = self.game 

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

195 return act 

196 

197 g.process_action(DominanceAction(tgt)) 

198 

199 return act 

200 

201 

202@register_character_to('imperial') 

203class SpAya(Character): 

204 skills = [WindWalk, Dominance] 

205 eventhandlers = [WindWalkHandler, DominanceHandler] 

206 maxlife = 4