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 

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 

16 

17# -- code -- 

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

19 

20 

21class UIMetaAccessor(object): 

22 def __init__(self, cls): 

23 self.for_cls = cls 

24 self.mro = cls.mro() 

25 

26 def __getattr__(self, name): 

27 for cls in self.mro: 

28 if cls not in UI_META: 

29 continue 

30 

31 try: 

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

33 return val 

34 except AttributeError: 

35 pass 

36 

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

38 

39 

40def ui_meta(for_cls: type): 

41 def decorate(cls: type): 

42 name = cls.__name__ 

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

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

45 

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

47 

48 # Type info is handled by plugin 

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

50 UI_META[for_cls] = cls 

51 return cls 

52 return decorate 

53 

54 

55# -----BEGIN COMMON FUNCTIONS----- 

56class UIMetaBase(GameViralContext): 

57 game: THBattle 

58 

59 def __init__(self): 

60 g = self.game 

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

62 try: 

63 self.me = g.find_character(me) 

64 except IndexError: 

65 self.me = me 

66 

67 def my_turn(self): 

68 g = self.game 

69 me = self.me 

70 try: 

71 act = g.action_stack[-1] 

72 except IndexError: 

73 return False 

74 

75 from thb import actions 

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

77 return False 

78 

79 if act.target is not me: return False 79 ↛ exitline 79 didn't return from function 'my_turn', because the return on line 79 wasn't executed

80 

81 if not act.in_user_input: return False 81 ↛ exitline 81 didn't return from function 'my_turn', because the return on line 81 wasn't executed

82 

83 return True 

84 

85 def limit1_skill_used(self, tag): 

86 me = self.me 

87 t = me.tags 

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

89 

90 def clickable(self): 

91 return False 

92 

93 def is_action_valid(self, c, tl): 

94 return (False, 'BUG!') 

95 

96 def card_desc(self, c): 

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

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

99 

100 from thb.cards.base import Card, HiddenCard 

101 if c.is_card(HiddenCard): return '一张牌' 101 ↛ exitline 101 didn't return from function 'card_desc', because the return on line 101 wasn't executed

102 

103 if c.suit == Card.SPADE: 

104 suit = '|r♠' 

105 elif c.suit == Card.HEART: 

106 suit = '|r|cb03a11ff♥' 

107 elif c.suit == Card.CLUB: 

108 suit = '|r♣' 

109 elif c.suit == Card.DIAMOND: 109 ↛ 111line 109 didn't jump to line 111, because the condition on line 109 was never false

110 suit = '|r|cb03a11ff♦' 

111 elif c.suit == Card.NOTSET: 

112 suit = '|r ' 

113 else: 

114 suit = '|r错误' 

115 

116 num = ' A23456789_JQK'[c.number] 

117 if num == '_': num = '10' 

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

119 

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

121 me = self.me 

122 from thb.cards.base import CardList 

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

124 c = cardcls() 

125 c.move_to(cl) 

126 return c 

127 

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

129 m = ch.ui_meta 

130 

131 cls: Type[Character] 

132 obj: Optional[Character] 

133 

134 if isinstance(ch, Character): 

135 cls, obj = ch.__class__, ch 

136 else: 

137 cls, obj = ch, None 

138 

139 rst = [] 

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

141 skills = list(cls.skills) 

142 if hasattr(cls, 'boss_skills'): 

143 skills.extend(cls.boss_skills) 

144 

145 if obj: 

146 skills.extend([ 

147 c for c in obj.skills 

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

149 ]) 

150 

151 for s in skills: 

152 sm = s.ui_meta 

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

154 

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

156 if notes: 

157 rst.append(notes) 

158 

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

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

161 ('CV', m.cv), 

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

163 ] if i[1]] 

164 

165 if tail: 

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

167 

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