Coverage for thb/meta/inputlets.py : 12%
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 --
4from typing import Sequence, List, cast
5from functools import wraps
6import logging
8# -- third party --
9# -- own --
10from client.base import Game as ClientGame
11from thb import actions
12from thb.actions import BaseActionStage
13from thb.cards.base import Skill, Card
14from thb.characters.base import Character
15from thb.mode import THBattle
16from thb.meta.common import ui_meta
19# -- code --
20log = logging.getLogger('Inputlets UI Meta')
23class ActionDisplayResult(Exception):
24 __slots__ = (
25 'valid',
26 'prompt',
27 'pl_selecting',
28 'pl_disabled',
29 'pl_selected',
30 )
32 def __init__(self, valid, prompt, pl_selecting, pl_disabled, pl_selected):
33 Exception.__init__(self)
34 self.valid = valid
35 self.prompt = prompt
36 self.pl_selecting = pl_selecting
37 self.pl_disabled = pl_disabled
38 self.pl_selected = pl_selected
41def walk_wrapped(g, cl, check_is_complete):
42 for c in cl:
43 if not isinstance(c, Skill):
44 continue
46 if check_is_complete:
47 try:
48 is_complete = c.ui_meta.is_complete
49 except Exception:
50 # skills that cannot combined with other skill
51 raise ActionDisplayResult(False, '您不能这样出牌', False, [], [])
53 try:
54 rst, reason = is_complete(g, c)
55 except Exception:
56 log.exception('card.ui_meta.is_complete error')
57 raise ActionDisplayResult(False, '[card.ui_meta.is_complete错误]', False, [], [])
59 if not rst:
60 raise ActionDisplayResult(False, reason, False, [], [])
62 walk_wrapped(g, c.associated_cards, True)
65def pasv_handle_card_selection(g, ilet, cards):
66 if not ilet.categories:
67 return [], ''
69 if cards:
70 walk_wrapped(g, cards, True)
72 from thb.cards.base import Skill
74 if cards[0].is_card(Skill) and not actions.skill_check(cards[0]):
75 raise ActionDisplayResult(False, '您不能这样出牌', False, [], [])
77 c = ilet.initiator.cond(cards)
78 c1, text = ilet.initiator.ui_meta.choose_card_text(g, ilet.initiator, cards)
79 assert c == c1, 'cond = %s, meta = %s' % (c, c1)
81 if not c:
82 raise ActionDisplayResult(False, text, False, [], [])
84 return cards, text
87def pasv_handle_player_selection(g, ilet, players):
88 if not ilet.candidates:
89 return False, [], [], ''
91 disables = [p for p in g.players if p not in ilet.candidates]
92 players = [p for p in players if p not in disables]
94 players, logic_valid = ilet.initiator.choose_player_target(players)
95 try:
96 ui_meta_valid, reason = ilet.initiator.ui_meta.target(players)
97 assert bool(logic_valid) == bool(ui_meta_valid), 'logic: %s, ui: %s' % (logic_valid, ui_meta_valid)
98 except Exception:
99 log.exception('act.ui_meta.target error')
100 raise ActionDisplayResult(False, '[act.ui_meta.target错误]', bool(ilet.candidates), disables, players)
102 if not logic_valid:
103 raise ActionDisplayResult(False, reason, True, disables, players)
105 return True, disables, players, reason
108def actv_handle_card_selection(g, act, cards):
109 if len(cards) != 1:
110 raise ActionDisplayResult(False, '请选择一张牌使用', False, [], [])
112 walk_wrapped(g, cards, False)
113 card = cards[0]
115 c = act.cond(cards)
116 c1, text = act.ui_meta.choose_card_text(g, act, cards)
117 assert c == c1, 'cond = %s, meta = %s' % (c, c1)
119 if not c:
120 raise ActionDisplayResult(False, text, False, [], [])
122 return card
125def actv_handle_target_selection(g: THBattle, stage: BaseActionStage, card: Card, players: Sequence[Character]):
126 plsel = False
127 selected: List[Character] = []
128 disables: List[Character] = []
130 me = g.find_character(cast(ClientGame, g).me)
131 tl, tl_valid = card.target(g, me, players)
132 if tl is not None:
133 selected = list(tl)
134 if card.target.__name__ in ('t_One', 't_OtherOne'):
135 for p in g.players:
136 act = stage.launch_card_cls(me, [p], card)
137 shootdown = act.action_shootdown()
138 if shootdown is not None:
139 if shootdown.ui_meta.target_independent:
140 reason = shootdown.ui_meta.shootdown_message
141 raise ActionDisplayResult(False, reason, False, [], [])
143 disables.append(p)
145 plsel = True
146 for i in disables:
147 try:
148 tl.remove(i)
149 except ValueError:
150 pass
152 try:
153 rst, reason = card.ui_meta.is_action_valid(g, [card], tl)
154 except Exception:
155 log.exception('card.ui_meta.is_action_valid error')
156 raise ActionDisplayResult(False, '[card.ui_meta.is_action_valid错误]', False, [], [])
158 if not rst:
159 raise ActionDisplayResult(False, reason, plsel, disables, selected)
161 if not tl_valid: # honor result of game logic
162 raise ActionDisplayResult(False, '您选择的目标不符合规则', plsel, disables, selected)
164 return tl, disables, reason
167def action_disp_func(f):
168 @wraps(f)
169 def wrapper(*a, **k):
170 try:
171 f(*a, **k)
172 raise Exception("Didn't raise ActionDisplayResult!")
173 except ActionDisplayResult as e:
174 return e
176 except Exception as e:
177 # Arghhh
178 log.exception(e)
179 return ActionDisplayResult(False, str(e), False, [], [])
181 wrapper.__name__ = f.__name__
182 return wrapper
185@ui_meta(actions.ActionInputlet)
186class ActionInputlet:
187 @action_disp_func
188 def passive_action_disp(self, ilet, skills, rawcards, params, players):
189 g = self.game
190 me = self.me
192 usage = getattr(ilet.initiator, 'card_usage', 'none')
194 if skills:
195 if any(not me.has_skill(s) for s in skills):
196 raise ActionDisplayResult(False, '您不能这样出牌', False, [], [])
197 cards = [actions.skill_wrap(me, skills, rawcards, params)]
198 usage = cards[0].usage if usage == 'launch' else usage
199 else:
200 cards = rawcards
202 cards, prompt_card = pasv_handle_card_selection(g, ilet, cards)
203 plsel, disables, players, prompt_target = pasv_handle_player_selection(g, ilet, players)
205 verify = getattr(ilet.initiator, 'ask_for_action_verify', None)
206 rst = not verify or verify(me, cards, players)
207 if not rst:
208 raise ActionDisplayResult(False, rst.ui_meta.shootdown_message, plsel, disables, players)
210 raise ActionDisplayResult(True, prompt_target or prompt_card, plsel, disables, players)
212 def passive_action_recommend(self, ilet):
213 me = self.me
215 if not ilet.categories: return
217 for c in me.showncards:
218 if not ilet.initiator.cond([c]): continue
219 return c
221 for c in me.cards:
222 if not ilet.initiator.cond([c]): continue
223 return c
225 @action_disp_func
226 def active_action_disp(self, ilet, skills, rawcards, params, players):
227 g = self.game
228 me = self.me
230 stage = ilet.initiator
232 if not skills and not rawcards:
233 raise ActionDisplayResult(False, stage.ui_meta.idle_prompt, False, [], [])
235 usage = getattr(ilet.initiator, 'card_usage', 'none')
237 if skills:
238 if any(not me.has_skill(s) for s in skills):
239 raise ActionDisplayResult(False, '您不能这样出牌', False, [], [])
240 cards = [actions.skill_wrap(me, skills, rawcards, params)]
241 usage = cards[0].usage if usage == 'launch' else usage
242 else:
243 cards = rawcards
245 card = actv_handle_card_selection(g, stage, cards)
246 players, disables, prompt = actv_handle_target_selection(g, stage, card, players)
248 act = stage.launch_card_cls(me, players, card)
250 shootdown = act.action_shootdown()
251 if shootdown is not None:
252 raise ActionDisplayResult(False, shootdown.ui_meta.shootdown_message, True, disables, players)
254 raise ActionDisplayResult(True, prompt, True, disables, players)