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 = ilet.initiator.game
191 usage = getattr(ilet.initiator, 'card_usage', 'none')
193 if skills:
194 if any(not g.me.has_skill(s) for s in skills):
195 raise ActionDisplayResult(False, '您不能这样出牌', False, [], [])
196 cards = [actions.skill_wrap(g.me, skills, rawcards, params)]
197 usage = cards[0].usage if usage == 'launch' else usage
198 else:
199 cards = rawcards
201 cards, prompt_card = pasv_handle_card_selection(g, ilet, cards)
202 plsel, disables, players, prompt_target = pasv_handle_player_selection(g, ilet, players)
204 verify = getattr(ilet.initiator, 'ask_for_action_verify', None)
205 rst = not verify or verify(g.me, cards, players)
206 if not rst:
207 raise ActionDisplayResult(False, rst.ui_meta.shootdown_message, plsel, disables, players)
209 raise ActionDisplayResult(True, prompt_target or prompt_card, plsel, disables, players)
211 def passive_action_recommend(self, ilet):
212 g = ilet.initiator.game
214 if not ilet.categories: return
216 for c in g.me.showncards:
217 if not ilet.initiator.cond([c]): continue
218 return c
220 for c in g.me.cards:
221 if not ilet.initiator.cond([c]): continue
222 return c
224 @action_disp_func
225 def active_action_disp(self, ilet, skills, rawcards, params, players):
226 g = ilet.initiator.game
228 stage = ilet.initiator
230 if not skills and not rawcards:
231 raise ActionDisplayResult(False, stage.ui_meta.idle_prompt, False, [], [])
233 usage = getattr(ilet.initiator, 'card_usage', 'none')
235 if skills:
236 if any(not g.me.has_skill(s) for s in skills):
237 raise ActionDisplayResult(False, '您不能这样出牌', False, [], [])
238 cards = [actions.skill_wrap(g.me, skills, rawcards, params)]
239 usage = cards[0].usage if usage == 'launch' else usage
240 else:
241 cards = rawcards
243 card = actv_handle_card_selection(g, stage, cards)
244 players, disables, prompt = actv_handle_target_selection(g, stage, card, players)
246 act = stage.launch_card_cls(g.me, players, card)
248 shootdown = act.action_shootdown()
249 if shootdown is not None:
250 raise ActionDisplayResult(False, shootdown.ui_meta.shootdown_message, True, disables, players)
252 raise ActionDisplayResult(True, prompt, True, disables, players)