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

## 117 statements 56 run 61 missing 2 excluded 0 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 TYPE_CHECKING

6

7# -- third party --

8# -- own --

9 from game.base import ActionShootdown

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

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

12 from thb.cards.basic import Attack

13 from thb.cards.definition import AttackCard, RejectCard

14 from thb.cards.spellcard import BaseDuel

15 from thb.characters.base import Character, register_character_to

16 from thb.mode import THBEventHandler

17

18# -- typing --

19 if TYPE_CHECKING:

20 from thb.thbkof import THBattleKOF # noqa: F401

21

22

23# -- code --

24 class DarknessDuel(BaseDuel):

25 pass

26

27

28 class DarknessAction(UserAction):

29 card_usage = 'launch'

30

31 def apply_action(self):

32 attacker, victim = self.target_list

33 src = self.source

34 g = self.game

35 tags = self.source.tags

36 tags['darkness_tag'] = tags['turn_count']

37

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

39 if cards:

40 c = cards[0]

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

42 else:

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

44

45 return True

46

47 def cond(self, cl):

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

49 c = cl[0]

50 if not c.associated_action: return False

51 return issubclass(c.associated_action, Attack)

52

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

54 attacker, victim = self.target_list

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

56

57 def is_valid(self):

58 tags = self.source.tags

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

60 return False

61

62 attacker, victim = self.target_list

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

64 return False

65

66 return True

67

68

69 class Darkness(Skill):

70 associated_action = DarknessAction

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

72 target = t_OtherN(2)

73 usage = 'drop'

74

75 def check(self):

76 cl = self.associated_cards

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

78 return False

79

80 if cl[0].is_card(Skill):

81 return False

82

83 return True

84

85

86 class DarknessKOF(Skill):

87 associated_action = None

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

89 target = t_None()

90

91

92 class DarknessKOFAction(UserAction):

93 def apply_action(self):

94 tgt = self.target

95 g = self.game

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

97 return True

98

99

100 class DarknessKOFLimit(ActionShootdown):

101 pass

102

103

104 class DarknessKOFHandler(THBEventHandler):

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

106 game: THBattleKOF

107

108 def handle(self, evt_type, arg):

109 if evt_type == 'character_debut':

110 old, new = arg

111 if new.has_skill(DarknessKOF):

112 g = self.game

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

114

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

116 src = arg.source

117 if not src:

118 return arg

119

120 g = self.game

121 opp = g.get_opponent(arg.source)

122 if opp.tags['darkness_kof_tag'] < g.turn_count:

123 return arg

124

125 card = arg.card

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

127 return arg

128

129 if card.is_card(RejectCard):

130 return arg

131

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

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

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

135 if opp in arg.target_list:

136 raise DarknessKOFLimit

137

138 return arg

139

140

141 class Cheating(Skill):

142 associated_action = None

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

144 target = t_None()

145

146

147 class CheatingDrawCards(DrawCards):

148 pass

149

150

151 class CheatingHandler(THBEventHandler):

152 interested = ['action_apply']

153 execute_before = ['CiguateraHandler']

154

155 def handle(self, evt_type, act):

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

157 tgt = act.target

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

159 g = self.game

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

161 return act

162

163

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

165 class Rumia(Character):

166 skills = [Darkness, Cheating]

167 eventhandlers = [CheatingHandler]

168 maxlife = 3

169

170

171@register_character_to('kof')

172 class RumiaKOF(Character):

173 skills = [DarknessKOF, Cheating]

174 eventhandlers = [DarknessKOFHandler, CheatingHandler]

175 maxlife = 3