# Coverage for thb/characters/rumia.py : 96%

## 115 statements 112 run 3 missing 0 excluded 3 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# -- third party --

6# -- own --

7 from game.base import ActionShootdown

8 from thb.actions import Damage, DrawCards, FinalizeStage, LaunchCard, UserAction, user_choose_cards

9 from thb.cards.base import PhysicalCard, Skill, t_None, t_OtherN

10 from thb.cards.basic import Attack

11 from thb.cards.definition import AttackCard, RejectCard

12 from thb.cards.spellcard import BaseDuel

13 from thb.characters.base import Character, register_character_to

14 from thb.mode import THBEventHandler

15

16

17# -- code --

18 class DarknessDuel(BaseDuel):

19 pass

20

21

22 class DarknessAction(UserAction):

23 card_usage = 'launch'

24

25 def apply_action(self):

26 attacker, victim = self.target_list

27 src = self.source

28 g = self.game

29 tags = self.source.tags

30 tags['darkness_tag'] = tags['turn_count']

31

32 cards = user_choose_cards(self, attacker, ('cards', 'showncards'))

33 if cards:

34 c = cards[0]

35 g.process_action(LaunchCard(attacker, [victim], c))

36 else:

37 g.process_action(Damage(src, attacker, 1))

38

39 return True

40

41 def cond(self, cl):

42 if len(cl) != 1: return False

43 c = cl[0]

44 if not c.associated_action: return False

45 return issubclass(c.associated_action, Attack)

46

47 def ask_for_action_verify(self, p, cl, tl):

48 attacker, victim = self.target_list

49 return LaunchCard(attacker, [victim], cl[0]).can_fire()

50

51 def is_valid(self):

52 tags = self.source.tags

53 if tags['turn_count'] <= tags['darkness_tag']:

54 return False

55

56 attacker, victim = self.target_list

57 if not LaunchCard(attacker, [victim], AttackCard()).can_fire():

58 return False

59

60 return True

61

62

63 class Darkness(Skill):

64 associated_action = DarknessAction

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

66 target = t_OtherN(2)

67 usage = 'drop'

68

69 def check(self):

70 cl = self.associated_cards

71 if not(cl and len(cl) == 1):

72 return False

73

74 if cl[0].is_card(Skill): 74 ↛ 75 line 74 didn't jump to line 75, because the condition on line 74 was never true

75 return False

76

77 return True

78

79

80 class DarknessKOF(Skill):

81 associated_action = None

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

83 target = t_None()

84

85

86 class DarknessKOFAction(UserAction):

87 def apply_action(self):

88 tgt = self.target

89 g = self.game

90 tgt.tags['darkness_kof_tag'] = max(g.turn_count, 1)

91 return True

92

93

94 class DarknessKOFLimit(ActionShootdown):

95 pass

96

97

98 class DarknessKOFHandler(THBEventHandler):

99 interested = ['character_debut', 'action_shootdown']

100

101 def handle(self, evt_type, arg):

102 if evt_type == 'character_debut':

103 old, new = arg

104 if new.has_skill(DarknessKOF):

105 g = self.game

106 g.process_action(DarknessKOFAction(new, new))

107

108 elif evt_type == 'action_shootdown' and isinstance(arg, LaunchCard):

109 src = arg.source

110 if not src: 110 ↛ 111 line 110 didn't jump to line 111, because the condition on line 110 was never true

111 return arg

112

113 g = self.game

114 opp = g.get_opponent(arg.source)

115 if opp.tags['darkness_kof_tag'] < g.turn_count: 115 ↛ 116 line 115 didn't jump to line 116, because the condition on line 115 was never true

116 return arg

117

118 card = arg.card

119 if not card.is_card(PhysicalCard) and 'treat_as' not in card.category:

120 return arg

121

122 if card.is_card(RejectCard):

123 return arg

124

125 # XXX: DollControl's second target do not count as target

126 # but in KOF the second target is always the launcher,

127 # and never be the opp, so the handle can be same.

128 if opp in arg.target_list:

129 raise DarknessKOFLimit

130

131 return arg

132

133

134 class Cheating(Skill):

135 associated_action = None

136 skill_category = ['character', 'passive', 'compulsory']

137 target = t_None()

138

139

140 class CheatingDrawCards(DrawCards):

141 pass

142

143

144 class CheatingHandler(THBEventHandler):

145 interested = ('action_apply',)

146 execute_before = ('CiguateraHandler', )

147

148 def handle(self, evt_type, act):

149 if evt_type == 'action_apply' and isinstance(act, FinalizeStage):

150 tgt = act.target

151 if tgt.has_skill(Cheating) and not tgt.dead:

152 g = self.game

153 g.process_action(CheatingDrawCards(tgt, 1))

154 return act

155

156

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

158 class Rumia(Character):

159 skills = [Darkness, Cheating]

160 eventhandlers = [CheatingHandler]

161 maxlife = 3

162

163

164@register_character_to('kof')

165 class RumiaKOF(Character):

166 skills = [DarknessKOF, Cheating]

167 eventhandlers = [DarknessKOFHandler, CheatingHandler]

168 maxlife = 3