Hide keyboard shortcuts

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 -*- 

2from __future__ import absolute_import 

3 

4# -- stdlib -- 

5# -- third party -- 

6# -- own -- 

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

8from thb.actions import ttags, user_choose_players 

9from thb.cards.base import Skill 

10from thb.cards.classes import t_None 

11from thb.characters.base import Character, register_character_to 

12from thb.inputlets import ChooseOptionInputlet 

13from thb.mode import THBEventHandler 

14 

15 

16# -- code -- 

17class DestructionImpulse(Skill): 

18 distance = 1 

19 associated_action = None 

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

21 target = t_None() 

22 

23 

24class 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 

36class 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) 77 ↛ exitline 77 didn't return from function 'choose_player_target', because the return on line 77 wasn't executed

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

79 

80 def cond(self, cards): 

81 return not cards 

82 

83 

84class FourOfAKind(Skill): 

85 associated_action = None 

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

87 target = t_None() 

88 

89 

90class 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 

105class 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 118 ↛ exitline 118 didn't return from function 'handle', because the return on line 118 wasn't executed

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') 

143class SpFlandre(Character): 

144 skills = [DestructionImpulse, FourOfAKind] 

145 eventhandlers = [DestructionImpulseHandler, FourOfAKindHandler] 

146 maxlife = 4