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 typing import Any, Dict, Optional, TYPE_CHECKING, Type, Union, Sequence 

6 

7# -- third party -- 

8# -- own -- 

9from game.base import GameViralContext 

10 

11# -- typing -- 

12if TYPE_CHECKING: 

13 from thb.mode import THBattle 

14 from thb.characters.base import Character # noqa: F401 

15 from thb.cards.base import Card # noqa: F401 

16 

17 

18# -- code -- 

19UI_META: Dict[type, Any] = {} 

20 

21 

22class UIMetaAccessor(object): 

23 def __init__(self, cls): 

24 self.for_cls = cls 

25 self.mro = cls.mro() 

26 

27 def __getattr__(self, name): 

28 for cls in self.mro: 

29 if cls not in UI_META: 

30 continue 

31 

32 try: 

33 val = getattr(UI_META[cls](), name) 

34 return val 

35 except AttributeError: 

36 pass 

37 

38 raise AttributeError(f'{self.for_cls.__name__}.{name}') 

39 

40 

41def ui_meta(for_cls: type): 

42 def decorate(cls: type): 

43 name = cls.__name__ 

44 if name in UI_META: 44 ↛ 45line 44 didn't jump to line 45, because the condition on line 44 was never true

45 raise Exception(f'{name} ui_meta redefinition!') 

46 

47 cls = type(name, (cls, UIMetaBase), {}) 

48 

49 # Type info is handled by plugin 

50 for_cls.ui_meta = UIMetaAccessor(for_cls) # type: ignore 

51 UI_META[for_cls] = cls 

52 return cls 

53 return decorate 

54 

55 

56# -----BEGIN COMMON FUNCTIONS----- 

57class UIMetaBase(GameViralContext): 

58 game: THBattle 

59 

60 def __init__(self): 

61 g = self.game 

62 me = g.runner.core.game.theone_of(g) 

63 try: 

64 self.me = g.find_character(me) 

65 except IndexError: 

66 self.me = me 

67 

68 def my_turn(self): 

69 g = self.game 

70 me = self.me 

71 try: 

72 act = g.action_stack[-1] 

73 except IndexError: 

74 return False 

75 

76 from thb import actions 

77 if not isinstance(act, actions.ActionStage): 

78 return False 

79 

80 if act.target is not me: return False 

81 

82 if not act.in_user_input: return False 

83 

84 return True 

85 

86 def limit1_skill_used(self, tag): 

87 me = self.me 

88 t = me.tags 

89 return t[tag] >= t['turn_count'] 

90 

91 def clickable(self): 

92 return False 

93 

94 def is_action_valid(self, c, tl): 

95 return (False, 'BUG!') 

96 

97 def card_desc(self, c): 

98 if isinstance(c, (list, tuple)): 

99 return '、'.join([self.card_desc(i) for i in c]) 

100 

101 from thb.cards.base import Card, HiddenCard 

102 if c.is_card(HiddenCard): return '一张牌' 

103 

104 if c.suit == Card.SPADE: 

105 suit = '|r♠' 

106 elif c.suit == Card.HEART: 

107 suit = '|r|cb03a11ff♥' 

108 elif c.suit == Card.CLUB: 

109 suit = '|r♣' 

110 elif c.suit == Card.DIAMOND: 

111 suit = '|r|cb03a11ff♦' 

112 elif c.suit == Card.NOTSET: 

113 suit = '|r ' 

114 else: 

115 suit = '|r错误' 

116 

117 num = ' A23456789_JQK'[c.number] 

118 if num == '_': num = '10' 

119 return suit + num + ' |G%s|r' % c.ui_meta.name 

120 

121 def build_handcard(self, cardcls, p=None): 

122 me = self.me 

123 from thb.cards.base import CardList 

124 cl = CardList(p or me, 'cards') 

125 c = cardcls() 

126 c.move_to(cl) 

127 return c 

128 

129 def accept_cards(self, cl: Sequence[Card]): 

130 g = self.game 

131 try: 

132 act = g.hybrid_stack[-1] 

133 if act.cond(cl): # type: ignore 

134 return True 

135 

136 except (IndexError, AttributeError): 

137 pass 

138 

139 return False 

140 

141 def char_desc(self, ch: Union[Character, Type[Character]]): 

142 m = ch.ui_meta 

143 

144 cls: Type[Character] 

145 obj: Optional[Character] 

146 

147 if isinstance(ch, Character): 

148 cls, obj = ch.__class__, ch 

149 else: 

150 cls, obj = ch, None 

151 

152 rst = [] 

153 rst.append('|DB%s %s 体力:%s|r' % (m.title, m.name, cls.maxlife)) 

154 skills = list(cls.skills) 

155 if hasattr(cls, 'boss_skills'): 

156 skills.extend(cls.boss_skills) 

157 

158 if obj: 

159 skills.extend([ 

160 c for c in obj.skills 

161 if 'character' in c.skill_category and c not in skills 

162 ]) 

163 

164 for s in skills: 

165 sm = s.ui_meta 

166 rst.append('|G%s|r:%s' % (sm.name, sm.description)) 

167 

168 notes = getattr(m, 'notes', '') 

169 if notes: 

170 rst.append(notes) 

171 

172 tail = ['%s:%s' % i for i in [ 

173 ('画师', m.illustrator), 

174 ('CV', m.cv), 

175 ('人物设计', m.designer), 

176 ] if i[1]] 

177 

178 if tail: 

179 rst.append('|DB(%s)|r' % ','.join(tail)) 

180 

181 return '\n\n'.join(rst)