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

5from functools import wraps 

6from typing import List, Sequence 

7import logging 

8 

9# -- third party -- 

10# -- own -- 

11from thb import actions 

12from thb.actions import BaseActionStage 

13from thb.cards.base import Card, Skill 

14from thb.characters.base import Character 

15from thb.meta.common import ui_meta 

16 

17 

18# -- code -- 

19log = logging.getLogger('Inputlets UI Meta') 

20 

21 

22class ActionDisplayResult(Exception): 

23 __slots__ = ( 

24 'valid', 

25 'prompt', 

26 'pl_selecting', 

27 'pl_disabled', 

28 'pl_selected', 

29 ) 

30 

31 def __init__(self, valid, prompt, pl_selecting, pl_disabled, pl_selected): 

32 Exception.__init__(self) 

33 self.valid = valid 

34 self.prompt = prompt 

35 self.pl_selecting = pl_selecting 

36 self.pl_disabled = pl_disabled 

37 self.pl_selected = pl_selected 

38 

39 

40def walk_wrapped(g, cl, check_is_complete): 

41 for c in cl: 

42 if not isinstance(c, Skill): 

43 continue 

44 

45 if check_is_complete: 

46 try: 

47 is_complete = c.ui_meta.is_complete 

48 except Exception: 

49 # skills that cannot combined with other skill 

50 raise ActionDisplayResult(False, '您不能这样出牌', False, [], []) 

51 

52 try: 

53 rst, reason = is_complete(c) 

54 except Exception: 

55 log.exception('card.ui_meta.is_complete error') 

56 raise ActionDisplayResult(False, '[card.ui_meta.is_complete错误]', False, [], []) 

57 

58 if not rst: 

59 raise ActionDisplayResult(False, reason, False, [], []) 

60 

61 walk_wrapped(g, c.associated_cards, True) 

62 

63 

64def action_disp_func(f): 

65 @wraps(f) 

66 def wrapper(*a, **k): 

67 try: 

68 f(*a, **k) 

69 raise Exception("Didn't raise ActionDisplayResult!") 

70 except ActionDisplayResult as e: 

71 return e 

72 

73 except Exception as e: 

74 log.exception("ActionInputlet meta failure") 

75 return ActionDisplayResult(False, str(e), False, [], []) 

76 

77 wrapper.__name__ = f.__name__ 

78 return wrapper 

79 

80 

81@ui_meta(actions.ActionInputlet) 

82class ActionInputlet: 

83 @action_disp_func 

84 def passive_action_disp(self, ilet, skills, rawcards, params, players): 

85 me = self.me 

86 

87 usage = getattr(ilet.initiator, 'card_usage', 'none') 

88 

89 if skills: 

90 if any(not me.has_skill(s) for s in skills): 

91 raise ActionDisplayResult(False, '您不能这样出牌', False, [], []) 

92 cards = [actions.skill_wrap(me, skills, rawcards, params)] 

93 usage = cards[0].usage if usage == 'launch' else usage 

94 else: 

95 cards = rawcards 

96 

97 cards, prompt_card = self.pasv_handle_card_selection(ilet, cards) 

98 plsel, disables, players, prompt_target = self.pasv_handle_player_selection(ilet, players) 

99 

100 verify = getattr(ilet.initiator, 'ask_for_action_verify', None) 

101 rst = not verify or verify(me, cards, players) 

102 if not rst: 

103 raise ActionDisplayResult(False, rst.ui_meta.shootdown_message, plsel, disables, players) 

104 

105 raise ActionDisplayResult(True, prompt_target or prompt_card, plsel, disables, players) 

106 

107 def pasv_handle_card_selection(self, ilet, cards): 

108 g = self.game 

109 

110 if not ilet.categories: 

111 return [], '' 

112 

113 if cards: 

114 walk_wrapped(g, cards, True) 

115 

116 from thb.cards.base import Skill 

117 

118 if cards[0].is_card(Skill) and not actions.skill_check(cards[0]): 

119 raise ActionDisplayResult(False, '您不能这样出牌', False, [], []) 

120 

121 c = ilet.initiator.cond(cards) 

122 c1, text = ilet.initiator.ui_meta.choose_card_text(g, ilet.initiator, cards) 

123 assert c == c1, 'cond = %s, meta = %s' % (c, c1) 

124 

125 if not c: 

126 raise ActionDisplayResult(False, text, False, [], []) 

127 

128 return cards, text 

129 

130 def pasv_handle_player_selection(self, ilet, players): 

131 g = self.game 

132 

133 if not ilet.candidates: 

134 return False, [], [], '' 

135 

136 disables = [p for p in g.players if p not in ilet.candidates] 

137 players = [p for p in players if p not in disables] 

138 

139 players, logic_valid = ilet.initiator.choose_player_target(players) 

140 try: 

141 ui_meta_valid, reason = ilet.initiator.ui_meta.target(players) 

142 assert bool(logic_valid) == bool(ui_meta_valid), 'logic: %s, ui: %s' % (logic_valid, ui_meta_valid) 

143 except Exception: 

144 log.exception('act.ui_meta.target error') 

145 raise ActionDisplayResult(False, '[act.ui_meta.target错误]', bool(ilet.candidates), disables, players) 

146 

147 if not logic_valid: 

148 raise ActionDisplayResult(False, reason, True, disables, players) 

149 

150 return True, disables, players, reason 

151 

152 def passive_action_recommend(self, ilet): 

153 me = self.me 

154 

155 if not ilet.categories: return 

156 

157 for c in me.showncards: 

158 if not ilet.initiator.cond([c]): continue 

159 return c 

160 

161 for c in me.cards: 

162 if not ilet.initiator.cond([c]): continue 

163 return c 

164 

165 @action_disp_func 

166 def active_action_disp(self, ilet, skills, rawcards, params, players): 

167 me = self.me 

168 

169 stage = ilet.initiator 

170 

171 if not skills and not rawcards: 

172 raise ActionDisplayResult(False, stage.ui_meta.idle_prompt, False, [], []) 

173 

174 usage = getattr(ilet.initiator, 'card_usage', 'none') 

175 

176 if skills: 

177 if any(not me.has_skill(s) for s in skills): 

178 raise ActionDisplayResult(False, '您不能这样出牌', False, [], []) 

179 cards = [actions.skill_wrap(me, skills, rawcards, params)] 

180 usage = cards[0].usage if usage == 'launch' else usage 

181 else: 

182 cards = rawcards 

183 

184 card = self.actv_handle_card_selection(stage, cards) 

185 players, disables, prompt = self.actv_handle_target_selection(stage, card, players) 

186 

187 act = stage.launch_card_cls(me, players, card) 

188 

189 shootdown = act.action_shootdown() 

190 if shootdown is not None: 

191 raise ActionDisplayResult(False, shootdown.ui_meta.shootdown_message, True, disables, players) 

192 

193 raise ActionDisplayResult(True, prompt, True, disables, players) 

194 

195 def actv_handle_card_selection(self, act, cards): 

196 g = self.game 

197 if len(cards) != 1: 

198 raise ActionDisplayResult(False, '请选择一张牌使用', False, [], []) 

199 

200 walk_wrapped(g, cards, False) 

201 card = cards[0] 

202 

203 c = act.cond(cards) 

204 c1, text = act.ui_meta.choose_card_text(g, act, cards) 

205 assert c == c1, 'cond = %s, meta = %s' % (c, c1) 

206 

207 if not c: 

208 raise ActionDisplayResult(False, text, False, [], []) 

209 

210 return card 

211 

212 def actv_handle_target_selection(self, stage: BaseActionStage, card: Card, players: Sequence[Character]): 

213 plsel = False 

214 selected: List[Character] = [] 

215 disables: List[Character] = [] 

216 g = self.game 

217 me = self.me 

218 

219 tl, tl_valid = card.target(me, players) 

220 if tl is not None: 

221 selected = list(tl) 

222 if card.target.__name__ in ('t_One', 't_OtherOne'): 

223 for p in g.players: 

224 act = stage.launch_card_cls(me, [p], card) 

225 shootdown = act.action_shootdown() 

226 if shootdown is not None: 

227 if shootdown.ui_meta.target_independent: 

228 reason = shootdown.ui_meta.shootdown_message 

229 raise ActionDisplayResult(False, reason, False, [], []) 

230 

231 disables.append(p) 

232 

233 plsel = True 

234 for i in disables: 

235 try: 

236 tl.remove(i) 

237 except ValueError: 

238 pass 

239 

240 try: 

241 rst, reason = card.ui_meta.is_action_valid(card, tl) 

242 except Exception: 

243 log.exception('card.ui_meta.is_action_valid error') 

244 raise ActionDisplayResult(False, '[card.ui_meta.is_action_valid错误]', False, [], []) 

245 

246 if not rst: 

247 raise ActionDisplayResult(False, reason, plsel, disables, selected) 

248 

249 if not tl_valid: # honor result of game logic 

250 raise ActionDisplayResult(False, '您选择的目标不符合规则', plsel, disables, selected) 

251 

252 return tl, disables, reason