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

2 

3# -- stdlib -- 

4from typing import Sequence, List, cast 

5from functools import wraps 

6import logging 

7 

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 

17 

18 

19# -- code -- 

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

21 

22 

23class ActionDisplayResult(Exception): 

24 __slots__ = ( 

25 'valid', 

26 'prompt', 

27 'pl_selecting', 

28 'pl_disabled', 

29 'pl_selected', 

30 ) 

31 

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 

39 

40 

41def walk_wrapped(g, cl, check_is_complete): 

42 for c in cl: 

43 if not isinstance(c, Skill): 

44 continue 

45 

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, [], []) 

52 

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, [], []) 

58 

59 if not rst: 

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

61 

62 walk_wrapped(g, c.associated_cards, True) 

63 

64 

65def pasv_handle_card_selection(g, ilet, cards): 

66 if not ilet.categories: 

67 return [], '' 

68 

69 if cards: 

70 walk_wrapped(g, cards, True) 

71 

72 from thb.cards.base import Skill 

73 

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

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

76 

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) 

80 

81 if not c: 

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

83 

84 return cards, text 

85 

86 

87def pasv_handle_player_selection(g, ilet, players): 

88 if not ilet.candidates: 

89 return False, [], [], '' 

90 

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] 

93 

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) 

101 

102 if not logic_valid: 

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

104 

105 return True, disables, players, reason 

106 

107 

108def actv_handle_card_selection(g, act, cards): 

109 if len(cards) != 1: 

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

111 

112 walk_wrapped(g, cards, False) 

113 card = cards[0] 

114 

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) 

118 

119 if not c: 

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

121 

122 return card 

123 

124 

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] = [] 

129 

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, [], []) 

142 

143 disables.append(p) 

144 

145 plsel = True 

146 for i in disables: 

147 try: 

148 tl.remove(i) 

149 except ValueError: 

150 pass 

151 

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, [], []) 

157 

158 if not rst: 

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

160 

161 if not tl_valid: # honor result of game logic 

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

163 

164 return tl, disables, reason 

165 

166 

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 

175 

176 except Exception as e: 

177 # Arghhh 

178 log.exception(e) 

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

180 

181 wrapper.__name__ = f.__name__ 

182 return wrapper 

183 

184 

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 

191 

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

193 

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 

201 

202 cards, prompt_card = pasv_handle_card_selection(g, ilet, cards) 

203 plsel, disables, players, prompt_target = pasv_handle_player_selection(g, ilet, players) 

204 

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) 

209 

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

211 

212 def passive_action_recommend(self, ilet): 

213 me = self.me 

214 

215 if not ilet.categories: return 

216 

217 for c in me.showncards: 

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

219 return c 

220 

221 for c in me.cards: 

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

223 return c 

224 

225 @action_disp_func 

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

227 g = self.game 

228 me = self.me 

229 

230 stage = ilet.initiator 

231 

232 if not skills and not rawcards: 

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

234 

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

236 

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 

244 

245 card = actv_handle_card_selection(g, stage, cards) 

246 players, disables, prompt = actv_handle_target_selection(g, stage, card, players) 

247 

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

249 

250 shootdown = act.action_shootdown() 

251 if shootdown is not None: 

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

253 

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