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 Dict, List, Optional, Sequence, TYPE_CHECKING, Tuple, Type 

6import logging 

7 

8# -- third party -- 

9# -- own -- 

10from game.base import Game, GameItem, Player 

11from server.base import Client, Game as ServerGame 

12from server.core import Core as ServerCore 

13from utils.misc import BatchList, exceptions 

14 

15 

16# -- typing -- 

17if TYPE_CHECKING: 

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

19 from thb.thbrole import THBRoleRole # noqa: F401 

20 

21 

22# -- code -- 

23log = logging.getLogger('thb.item') 

24 

25 

26@GameItem.register 

27class ImperialChoice(GameItem): 

28 key = 'imperial-choice' 

29 args = [str] 

30 

31 def __init__(self, char: str): 

32 if char == 'Akari' or char not in Character.classes: 

33 raise exceptions.CharacterNotFound 

34 

35 self.char_cls = Character.classes[char] 

36 

37 @property 

38 def title(self): 

39 return '选将卡(%s)' % self.char_cls.ui_meta.name 

40 

41 @property 

42 def description(self): 

43 return '你可以选择%s出场。2v2模式不可用。' % self.char_cls.ui_meta.name 

44 

45 def should_usable(self, core: ServerCore, g: ServerGame, u: Client): 

46 from thb.thb2v2 import THBattle2v2 

47 if isinstance(g, THBattle2v2): 

48 raise exceptions.IncorrectGameMode 

49 

50 core = g.core 

51 items = core.item.items_of(g) 

52 

53 for l in items.values(): 

54 if self.sku in l: 

55 raise exceptions.ChooseCharacterConflict 

56 

57 @classmethod 

58 def get_chosen(cls, items: Dict[Player, List[GameItem]], pl: BatchList[Player]) -> Dict[Player, Type[Character]]: 

59 chosen: Dict[Player, Type[Character]] = {} 

60 

61 for p in pl: 

62 if p not in items: 62 ↛ 65line 62 didn't jump to line 65, because the condition on line 62 was never false

63 continue 

64 

65 for i in items[p]: 

66 if not isinstance(i, cls): 

67 continue 

68 

69 chosen[p] = i.char_cls 

70 break 

71 

72 return chosen 

73 

74 

75@GameItem.register 

76class ImperialRole(GameItem): 

77 key = 'imperial-role' 

78 args = [str] 

79 

80 def __init__(self, role: str): 

81 if role not in ('attacker', 'accomplice', 'curtain', 'boss'): 81 ↛ 82line 81 didn't jump to line 82, because the condition on line 81 was never true

82 raise exceptions.InvalidItemSKU 

83 

84 self.role = role 

85 mapping = { 

86 'attacker': '城管', 

87 'boss': 'BOSS', 

88 'accomplice': '道中', 

89 'curtain': '黑幕', 

90 } 

91 self.disp_name = mapping[role] 

92 

93 @property 

94 def title(self): 

95 return '身份卡(%s)' % self.disp_name 

96 

97 @property 

98 def description(self): 

99 return '你可以选择%s身份。身份场可用。' % self.disp_name 

100 

101 def should_usable(self, core: ServerCore, g: ServerGame, u: Client): 

102 from thb.thbrole import THBattleRole 

103 if not isinstance(g, THBattleRole): 103 ↛ 106line 103 didn't jump to line 106

104 raise exceptions.IncorrectGameMode 

105 

106 threshold = { 

107 'attacker': 4, 

108 'boss': 1, 

109 'accomplice': 2, 

110 'curtain': 1, 

111 } 

112 core = g.core 

113 params = core.game.params_of(g) 

114 if params['double_curtain']: 

115 threshold['curtain'] += 1 

116 threshold['attacker'] -= 1 

117 

118 threshold[self.id] -= 1 

119 

120 items = core.item.items_of(g) 

121 uid = core.auth.uid_of(u) 

122 for _uid, l in items: 

123 for i in l: 

124 i = GameItem.from_sku(i) 

125 if not isinstance(i, self.__class__): 

126 continue 

127 

128 if _uid == uid: 

129 raise exceptions.IdentityAlreadyChosen 

130 

131 assert i.id in threshold 

132 

133 threshold[i.id] -= 1 

134 

135 if any(i < 0 for i in threshold.values()): 

136 raise exceptions.ChooseIdentityConflict 

137 

138 @classmethod 

139 def get_chosen(cls, items: Dict[Player, List[GameItem]], pl: Sequence[Player]) -> List[Tuple[Player, THBRoleRole]]: 

140 from thb.thbrole import THBRoleRole as T 

141 

142 mapping = { 

143 'boss': T.BOSS, 

144 'attacker': T.ATTACKER, 

145 'accomplice': T.ACCOMPLICE, 

146 'curtain': T.CURTAIN, 

147 } 

148 

149 rst = [] 

150 for p in pl: 

151 if p not in items: 151 ↛ 154line 151 didn't jump to line 154, because the condition on line 151 was never false

152 continue 

153 

154 for i in items[p]: 

155 if not isinstance(i, cls): 

156 continue 

157 

158 rst.append((p, mapping[i.role])) 

159 

160 return rst 

161 

162 

163@GameItem.register 

164class European(GameItem): 

165 key = 'european' 

166 

167 title = '欧洲卡' 

168 description = 'Roll点保证第一。身份场不可用。' 

169 

170 def __init__(self): 

171 pass 

172 

173 def should_usable(self, core: ServerCore, g: ServerGame, u: Client): 

174 cls = self.__class__ 

175 

176 from thb.thbrole import THBattleRole 

177 if isinstance(g, THBattleRole): 177 ↛ 178line 177 didn't jump to line 178, because the condition on line 177 was never true

178 raise exceptions.IncorrectGameMode 

179 

180 items = core.item.items_of(g) 

181 

182 for uid, l in items.items(): 

183 if any(isinstance(i, cls) for i in l): 183 ↛ exit,   183 ↛ 1822 missed branches: 1) line 183 didn't finish the generator expression on line 183, 2) line 183 didn't jump to line 182, because the condition on line 183 was never false

184 raise exceptions.EuropeanConflict 

185 

186 @classmethod 

187 def get_european(cls, g: Game, items: Dict[Player, List[GameItem]]) -> Optional[Player]: 

188 for p, l in items.items(): 

189 for i in l: 189 ↛ 188line 189 didn't jump to line 188, because the loop on line 189 didn't complete

190 if isinstance(i, cls): 190 ↛ 189line 190 didn't jump to line 189, because the condition on line 190 was never false

191 return p 

192 

193 return None