# Coverage for thb/meta/inputlets.py : 12%

## 169 statements 27 run 142 missing 0 excluded 0 partial

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

4 from typing import Sequence, List, cast

5 from functools import wraps

6 import logging

7

8# -- third party --

9# -- own --

10 from client.base import Game as ClientGame

11 from thb import actions

12 from thb.actions import BaseActionStage

13 from thb.cards.base import Skill, Card

14 from thb.characters.base import Character

15 from thb.mode import THBattle

16 from thb.meta.common import ui_meta

17

18

19# -- code --

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

21

22

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

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

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

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

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

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

167 def 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)

186 class 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)