Coverage for thb/characters/sp_aya.py : 25%
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 game.base import ActionShootdown, InputTransaction
7from thb.actions import ActionStage, ActionStageLaunchCard, DrawCards, DropCardStage, FinalizeStage
8from thb.actions import GenericAction, LaunchCard, PlayerTurn, ShowCards, UserAction, ask_for_action
9from thb.cards.base import Card, Skill, VirtualCard
10from thb.cards.classes import PhysicalCard, t_None, t_Self
11from thb.characters.base import Character, register_character_to
12from thb.inputlets import ChooseOptionInputlet
13from thb.mode import THBEventHandler
16# -- code --
17class WindWalkLaunch(ActionStageLaunchCard):
18 pass
21class WindWalkSkipAction(GenericAction):
22 def apply_action(self) -> bool:
23 g = self.game
24 ActionStage.force_break(g)
25 turn = PlayerTurn.get_current(g)
26 try:
27 turn.pending_stages.remove(DropCardStage)
28 turn.pending_stages.remove(FinalizeStage)
29 except Exception:
30 pass
32 return True
35class WindWalkAction(UserAction):
36 card_usage = 'launch'
38 def apply_action(self):
39 g = self.game
40 tgt = self.target
42 while True:
43 dc = DrawCards(tgt, 1)
44 g.process_action(dc)
45 c, = dc.cards
46 self.card = c
47 g.process_action(ShowCards(tgt, [c]))
49 with InputTransaction('ActionStageAction', [tgt]) as trans:
50 p, rst = ask_for_action(
51 self, [tgt], ('cards', 'showncards'), g.players, trans=trans
52 )
54 if p is not tgt:
55 g.process_action(WindWalkSkipAction(tgt, tgt))
56 break
58 assert p
59 assert rst
61 cl, tl = rst
62 g.players.reveal(cl)
63 c, = cl
65 g.process_action(WindWalkLaunch(p, tl, c))
67 return True
69 def cond(self, cl):
70 if not (cl and len(cl) == 1):
71 return False
73 return bool(cl[0].associated_action) and [self.card] == VirtualCard.unwrap(cl)
75 def ask_for_action_verify(self, p, cl, tl):
76 assert len(cl) == 1
77 return WindWalkLaunch(p, tl, cl[0]).can_fire()
79 def choose_player_target(self, tl):
80 return tl, True
83class WindWalkTargetLimit(ActionShootdown):
84 pass
87class WindWalkHandler(THBEventHandler):
88 interested = ['action_apply', 'action_shootdown']
90 def handle(self, evt_type, act):
91 if evt_type == 'action_apply' and isinstance(act, LaunchCard):
92 src = act.source
93 if act.card.is_card(WindWalk):
94 return act
96 if not src.has_skill(WindWalk):
97 return act
99 src.tags['windwalk_last_targets'] = set(act.target_list)
101 elif evt_type == 'action_apply' and isinstance(act, PlayerTurn):
102 src = act.source
103 if not src.has_skill(WindWalk):
104 return act
106 src.tags['windwalk_last_targets'] = set()
108 elif evt_type == 'action_shootdown' and isinstance(act, LaunchCard):
109 g = self.game
110 if not isinstance(g.action_stack[-1], WindWalkAction):
111 return act
113 src, tl = act.source, set(act.target_list)
114 last_tl = src.tags['windwalk_last_targets'] or set()
116 if not tl <= last_tl:
117 raise WindWalkTargetLimit
119 return act
121 return act
124class WindWalk(Skill):
125 associated_action = WindWalkAction
126 skill_category = ['character', 'active']
127 target = t_Self()
128 usage = 'drop'
130 def check(self):
131 cl = self.associated_cards
132 if not(cl and len(cl) == 1):
133 return False
135 if cl[0].is_card(Skill):
136 return False
138 return True
141class Dominance(Skill):
142 associated_action = None
143 skill_category = ['character', 'passive']
144 target = t_None()
147class DominanceAction(PlayerTurn):
148 pass
151class DominanceHandler(THBEventHandler):
152 interested = ['action_after', 'action_apply']
154 def handle(self, evt_type, act):
155 if evt_type == 'action_apply' and isinstance(act, PlayerTurn):
156 t = act.target.tags
157 t['dominance_suits'] = set()
158 t['dominance_suit_SPADE'] = False
159 t['dominance_suit_CLUB'] = False
160 t['dominance_suit_HEART'] = False
161 t['dominance_suit_DIAMOND'] = False
163 elif evt_type == 'action_apply' and isinstance(act, LaunchCard):
164 if not act.source.has_skill(Dominance):
165 return act
167 card = act.card
168 if not card.is_card(PhysicalCard):
169 return act
171 suit = card.suit
172 if suit not in (Card.SPADE, Card.CLUB, Card.HEART, Card.DIAMOND):
173 return act
175 try:
176 t = act.source.tags
177 t['dominance_suits'].add(suit)
178 t['dominance_suit_%s' % Card.SUIT_REV[suit]] = True
180 except AttributeError:
181 pass
183 elif evt_type == 'action_after' and isinstance(act, PlayerTurn):
184 tgt = act.target
185 if not tgt.has_skill(Dominance):
186 return act
188 if len(tgt.tags['dominance_suits'] or set()) != 4:
189 return act
191 g = self.game
192 if not g.user_input([tgt], ChooseOptionInputlet(self, (False, True))):
193 return act
195 g.process_action(DominanceAction(tgt))
197 return act
200@register_character_to('imperial')
201class SpAya(Character):
202 skills = [WindWalk, Dominance]
203 eventhandlers = [WindWalkHandler, DominanceHandler]
204 maxlife = 4