# Coverage for thb/item.py : 41%

## 109 statements 54 run 55 missing 3 excluded 7 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 from __future__ import annotations

3

4# -- stdlib --

5 from typing import Dict, List, Optional, Sequence, TYPE_CHECKING, Tuple, Type

6 import logging

7

8# -- third party --

9# -- own --

10 from game.base import Game, GameItem, Player

11 from server.base import Client, Game as ServerGame

12 from server.core import Core as ServerCore

13 from utils.misc import BatchList, exceptions

14

15

16# -- typing --

17 if TYPE_CHECKING:

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

19 from thb.thbrole import THBRoleRole # noqa: F401

20

21

22# -- code --

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

24

25

26@GameItem.register

27 class 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 items = core.item.items_of(g)

51

52 for l in items.values():

53 if self.sku in l:

54 raise exceptions.ChooseCharacterConflict

55

56 @classmethod

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

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

59

60 for p in pl:

61 if p not in items:

62 continue

63

64 for i in items[p]:

65 if not isinstance(i, cls):

66 continue

67

68 chosen[p] = i.char_cls

69 break

70

71 return chosen

72

73

74@GameItem.register

75 class ImperialRole(GameItem):

76 key = 'imperial-role'

77 args = [str]

78

79 def __init__(self, role: str):

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

81 raise exceptions.InvalidItemSKU

82

83 self.role = role

84 mapping = {

85 'attacker': '城管',

86 'boss': 'BOSS',

87 'accomplice': '道中',

88 'curtain': '黑幕',

89 }

90 self.disp_name = mapping[role]

91

92 @property

93 def title(self):

94 return '身份卡（%s）' % self.disp_name

95

96 @property

97 def description(self):

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

99

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

101 from thb.thbrole import THBattleRole

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

103 raise exceptions.IncorrectGameMode

104

105 threshold = {

106 'attacker': 4,

107 'boss': 1,

108 'accomplice': 2,

109 'curtain': 1,

110 }

111 params = core.game.params_of(g)

112 if params['double_curtain']:

113 threshold['curtain'] += 1

114 threshold['attacker'] -= 1

115

116 threshold[self.role] -= 1

117

118 items = core.item.items_of(g)

119 uid = core.auth.uid_of(u)

120 for _uid, l in items.items():

121 for i in l:

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

123 continue

124

125 if _uid == uid:

126 raise exceptions.RoleAlreadyChosen

127

128 assert i.role in threshold

129

130 threshold[i.role] -= 1

131

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

133 raise exceptions.ChooseRoleConflict

134

135 @classmethod

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

137 from thb.thbrole import THBRoleRole as T

138

139 mapping = {

140 'boss': T.BOSS,

141 'attacker': T.ATTACKER,

142 'accomplice': T.ACCOMPLICE,

143 'curtain': T.CURTAIN,

144 }

145

146 rst = []

147 for p in pl:

148 if p not in items:

149 continue

150

151 for i in items[p]:

152 if not isinstance(i, cls):

153 continue

154

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

156

157 return rst

158

159

160@GameItem.register

161 class European(GameItem):

162 key = 'european'

163

164 title = '欧洲卡'

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

166

167 def __init__(self):

168 pass

169

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

171 cls = self.__class__

172

173 from thb.thbrole import THBattleRole

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

175 raise exceptions.IncorrectGameMode

176

177 items = core.item.items_of(g)

178

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

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

181 raise exceptions.EuropeanConflict

182

183 @classmethod

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

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

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

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

188 return p

189

190 return None