# Coverage for thb/characters/sp_flandre.py : 29%

## 96 statements 38 run 58 missing 0 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 absolute_import

3

4# -- stdlib --

5# -- third party --

6# -- own --

7 from thb.actions import Damage, GenericAction, LaunchCard, LifeLost, MaxLifeChange, FinalizeStage

8 from thb.actions import ttags, user_choose_players

9 from thb.cards.base import Skill

10 from thb.cards.classes import t_None

11 from thb.characters.base import Character, register_character_to

12 from thb.inputlets import ChooseOptionInputlet

13 from thb.mode import THBEventHandler

14

15

16# -- code --

17 class DestructionImpulse(Skill):

18 distance = 1

19 associated_action = None

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

21 target = t_None()

22

23

24 class DestructionImpulseAction(GenericAction):

25 def apply_action(self):

26 src = self.source

27 tgt = self.target

28 g = self.game

29

30 g.process_action(Damage(src, tgt))

31 g.process_action(LifeLost(src, src))

32

33 return True

34

35

36 class DestructionImpulseHandler(THBEventHandler):

37 interested = ['action_after']

38 execute_before = ['CiguateraHandler']

39

40 def handle(self, evt_type, act):

41 if evt_type == 'action_after' and isinstance(act, Damage):

42 src = act.source

43 if not src: return act

44 if not src.has_skill(DestructionImpulse): return act

45

46 g = self.game

47 ttags(src)['destruction_tag'] = True

48

49 elif evt_type == 'action_after' and isinstance(act, FinalizeStage):

50 tgt = act.target

51 if not tgt.has_skill(DestructionImpulse): return act

52

53 g = self.game

54 if ttags(tgt)['destruction_tag']: return act

55

56 dist = LaunchCard.calc_distance(g, tgt, DestructionImpulse(tgt))

57 dist.pop(tgt, '')

58

59 for k in dist:

60 dist[k] = max(dist[k], 0)

61

62 nearest = min(dist.values())

63 candidates = [p for p, d in dist.items() if d == nearest]

64 candidates = [p for p in g.players if p in candidates] # order matters

65

66 if len(candidates) > 1:

67 pl = user_choose_players(self, tgt, candidates)

68 p = pl[0] if pl else candidates[0]

69 else:

70 p = candidates[0]

71

72 g.process_action(DestructionImpulseAction(tgt, p))

73

74 return act

75

76 def choose_player_target(self, tl):

77 if not tl: return (tl, False)

78 return (tl[-1:], True)

79

80 def cond(self, cards):

81 return not cards

82

83

84 class FourOfAKind(Skill):

85 associated_action = None

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

87 target = t_None()

88

89

90 class FourOfAKindAction(GenericAction):

91 def __init__(self, source, target_act):

92 self.source = source

93 self.target_act = target_act

94 self.target = target_act.target

95

96 def apply_action(self):

97 g = self.game

98 src = self.source

99 self.target_act.cancelled = True

100 g.process_action(MaxLifeChange(src, src, -1))

101

102 return True

103

104

105 class FourOfAKindHandler(THBEventHandler):

106 interested = ['action_before']

107 execute_before = ['WineHandler']

108 execute_after = [

109 'RepentanceStickHandler',

110 'DeathSickleHandler',

111 'CriticalStrikeHandler',

112 'SadistHandler',

113 'PerfectFreezeHandler',

114 ]

115

116 def handle(self, evt_type, act):

117 if evt_type == 'action_before' and isinstance(act, Damage):

118 if act.cancelled: return act

119

120 src = act.source

121 tgt = act.target

122 g = self.game

123 if tgt.has_skill(FourOfAKind) and act.amount <= tgt.life:

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

125 g.process_action(FourOfAKindAction(tgt, act))

126

127 if src and src.has_skill(FourOfAKind):

128 g = self.game

129

130 for a in reversed(g.action_stack):

131 if isinstance(a, LaunchCard):

132 break

133 else:

134 return act

135

136 if src.life == 1:

137 act.amount += 1

138

139 return act

140

141

142@register_character_to('common')

143 class SpFlandre(Character):

144 skills = [DestructionImpulse, FourOfAKind]

145 eventhandlers = [DestructionImpulseHandler, FourOfAKindHandler]

146 maxlife = 4