# Coverage for thb/item.py : 51%

## 112 statements 66 run 46 missing 3 excluded 9 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 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 ↛ 65 line 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

76 class 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 ↛ 82 line 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 ↛ 106 line 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 ↛ 154 line 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

164 class 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 ↛ 178 line 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 ↛ 182 2 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 ↛ 188 line 189 didn't jump to line 188, because the loop on line 189 didn't complete

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

191 return p

192

193 return None