# Coverage for thb/characters/kokoro.py : 95%

## 130 statements 125 run 5 missing 0 excluded 4 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

3# -- stdlib --

4# -- third party --

5# -- own --

6 from thb.actions import ActionStage, DropCards, ShowCards, UserAction, migrate_cards

7 from thb.actions import user_choose_cards

8 from thb.cards.base import Card, Skill

9 from thb.cards.classes import t_None, t_OtherOne

10 from thb.characters.base import Character, register_character_to

11 from thb.inputlets import ChooseOptionInputlet, HopeMaskInputlet, HopeMaskKOFInputlet

12 from thb.mode import THBEventHandler

13

14

15# -- code --

16 class BaseHopeMaskAction(UserAction):

17

18 def apply_action(self):

19 tgt = self.target

20 g = self.game

21 n = 1 + tgt.maxlife - tgt.life

22 cards = g.deck.getcards(n)

23

24 tgt.reveal(cards)

25 putback, acquire = g.user_input([tgt], self.inputlet_cls(self, cards), timeout=20)

26 for c in acquire: 26 ↛ 27 line 26 didn't jump to line 27, because the loop on line 26 never started

27 c.detach()

28

29 assert not putback or set(putback) == set(g.deck.getcards(len(putback)))

30

31 deck = g.deck.cards

32 for i, c in enumerate(putback):

33 deck[i] = c

34

35 assert not putback or putback == g.deck.getcards(len(putback))

36

37 if acquire: 37 ↛ 38 line 37 didn't jump to line 38, because the condition on line 37 was never true

38 g.process_action(ShowCards(tgt, acquire))

39 migrate_cards(acquire, tgt.cards)

40

41 self.acquire = acquire

42

43 return True

44

45

46 class HopeMaskAction(BaseHopeMaskAction):

47 inputlet_cls = HopeMaskInputlet

48

49

50 class HopeMaskKOFAction(BaseHopeMaskAction):

51 inputlet_cls = HopeMaskKOFInputlet

52

53

54 class BaseHopeMaskHandler(THBEventHandler):

55 interested = ['action_apply']

56

57 def handle(self, evt_type, act):

58 if evt_type == 'action_apply' and isinstance(act, ActionStage):

59 tgt = act.target

60 if not tgt.has_skill(self.skill): return act

61 g = self.game

62 if not g.user_input([tgt], ChooseOptionInputlet(self, (False, True))):

63 return act

64 g.process_action(self.action(tgt, tgt))

65

66 return act

67

68

69 class HopeMask(Skill):

70 associated_action = None

71 skill_category = ['character', 'passive']

72 target = t_None()

73

74

75 class HopeMaskKOF(Skill):

76 associated_action = None

77 skill_category = ['character', 'passive']

78 target = t_None()

79

80

81 class HopeMaskHandler(BaseHopeMaskHandler):

82 skill = HopeMask

83 action = HopeMaskAction

84

85

86 class HopeMaskKOFHandler(BaseHopeMaskHandler):

87 skill = HopeMaskKOF

88 action = HopeMaskKOFAction

89

90

91 class BaseDarkNohAction(UserAction):

92 card_usage = 'drop'

93

94 def apply_action(self):

95 src, tgt = self.source, self.target

96 g = self.game

97

98 src.tags['darknoh_tag'] = src.tags['turn_count']

99 sk = self.associated_card

100 card = sk.associated_cards[0]

101 self.card = card

102 migrate_cards([sk], tgt.showncards, unwrap=True)

103 self.n = n = len(tgt.cards) + len(tgt.showncards) - tgt.life

104 if n <= 0: return True

105

106 cards = user_choose_cards(self, tgt, ('cards', 'showncards'))

107 if not cards:

108 cl = list(tgt.cards) + list(tgt.showncards)

109 try:

110 cl.remove(card)

111 except Exception:

112 pass

113

114 cards = cl[:n]

115

116 g.players.reveal(cards)

117 g.process_action(DropCards(src, tgt, cards))

118

119 return True

120

121 def cond(self, cards):

122 if len(cards) != self.n or self.card in cards:

123 return False

124

125 if any([c.is_card(Skill) for c in cards]):

126 return False

127

128 return True

129

130

131 class DarkNohAction(BaseDarkNohAction):

132

133 def is_valid(self):

134 src = self.source

135 tgt = self.target

136

137 if src.tags['darknoh_tag'] >= src.tags['turn_count']:

138 return False

139

140 if src.life > tgt.life:

141 return False

142

143 return True

144

145

146 class DarkNohKOFAction(BaseDarkNohAction):

147

148 def is_valid(self):

149 src = self.source

150 tgt = self.target

151

152 if src.tags['darknoh_tag'] > 0:

153 return False

154

155 if src.life > tgt.life:

156 return False

157

158 return True

159

160

161 class BaseDarkNoh(Skill):

162 no_drop = True

163 skill_category = ['character', 'active']

164 target = t_OtherOne()

165 usage = 'handover'

166

167 def check(self):

168 cards = self.associated_cards

169 if len(cards) != 1: return False

170 c = cards[0]

171 if c.resides_in is None: return False 171 ↛ exit line 171 didn't return from function 'check', because the return on line 171 wasn't executed

172 if c.resides_in.type not in ('cards', 'showncards', 'equips'): return False 172 ↛ exit line 172 didn't return from function 'check', because the return on line 172 wasn't executed

173 if c.suit not in (Card.SPADE, Card.CLUB): return False

174 return True

175

176

177 class DarkNoh(BaseDarkNoh):

178 associated_action = DarkNohAction

179

180

181 class DarkNohKOF(BaseDarkNoh):

182 associated_action = DarkNohKOFAction

183

184

185@register_character_to('common', '-kof')

186 class Kokoro(Character):

187 skills = [HopeMask, DarkNoh]

188 eventhandlers = [HopeMaskHandler]

189 maxlife = 3

190

191

192@register_character_to('kof')

193 class KokoroKOF(Character):

194 skills = [HopeMaskKOF, DarkNohKOF]

195 eventhandlers = [HopeMaskKOFHandler]

196 maxlife = 3