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

2 

3# -- stdlib -- 

4# -- third party -- 

5# -- own -- 

6from thb.actions import Damage, DrawCards, ForEach, LaunchCard, PlayerDeath, UserAction, PlayerTurn 

7from thb.actions import user_choose_players 

8from thb.cards.base import Skill 

9from thb.cards.classes import AttackCard, Duel, InstantSpellCardAction, Reject, TreatAs, t_None 

10from thb.characters.base import Character, register_character_to 

11from thb.inputlets import ChooseOptionInputlet 

12from thb.mode import THBEventHandler 

13 

14 

15# -- code -- 

16class ReversedScales(TreatAs, Skill): 

17 skill_category = ['character', 'active', 'compulsory'] 

18 treat_as = AttackCard 

19 

20 def check(self): 

21 cl = self.associated_cards 

22 if not cl or len(cl) != 1: 

23 return False 

24 

25 g = self.game 

26 if PlayerTurn.get_current(g).target is self.character: 

27 return False 

28 

29 return cl[0].resides_in.type in ('cards', 'showncards') 

30 

31 

32class Sadist(Skill): 

33 associated_action = None 

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

35 target = t_None() 

36 

37 

38class SadistKOF(Skill): 

39 associated_action = None 

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

41 target = t_None() 

42 

43 

44class SadistKOFDrawCards(DrawCards): 

45 pass 

46 

47 

48class SadistKOFDamageAction(UserAction): 

49 def apply_action(self): 

50 g = self.game 

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

52 return g.process_action(Damage(src, tgt, 1)) 

53 

54 

55class SadistKOFHandler(THBEventHandler): 

56 interested = ['action_after', 'character_debut'] 

57 execute_after = ['DeathHandler'] 

58 

59 def handle(self, evt_type, arg): 

60 if evt_type == 'action_after' and isinstance(arg, PlayerDeath): 

61 tgt = arg.target 

62 g = self.game 

63 op = g.get_opponent(tgt) 

64 if arg.source is op and op.has_skill(SadistKOF): 

65 g.process_action(SadistKOFDrawCards(op, 2)) 

66 op.tags['sadist_kof_fire'] = True 

67 

68 elif evt_type == 'character_debut': 

69 old, new = arg 

70 if not old: return arg 

71 

72 g = self.game 

73 op = g.get_opponent(new) 

74 

75 if op.has_skill(SadistKOF) and op.tags['sadist_kof_fire']: 

76 op.tags['sadist_kof_fire'] = False 

77 g.process_action(SadistKOFDamageAction(op, new)) 

78 

79 return arg 

80 

81 

82class ReversedScalesAction(UserAction): 

83 def __init__(self, target, action): 

84 self.source = target 

85 self.target = target 

86 self.action = action 

87 

88 def apply_action(self): 

89 self.action.__class__ = Duel 

90 return True 

91 

92 

93class ReversedScalesHandler(THBEventHandler): 

94 interested = ['action_before'] 

95 execute_before = ['MaidenCostumeHandler'] 

96 

97 def handle(self, evt_type, act): 

98 if evt_type != 'action_before': 98 ↛ 99line 98 didn't jump to line 99, because the condition on line 98 was never true

99 return act 

100 

101 if not isinstance(act, InstantSpellCardAction): 

102 return act 

103 

104 if isinstance(act, Reject): 

105 # HACK 

106 return act 

107 

108 if ForEach.is_group_effect(act): 

109 return act 

110 

111 src = act.source 

112 tgt = act.target 

113 

114 if not src or tgt is src: 

115 return act 

116 

117 if not tgt.has_skill(ReversedScales): 

118 return act 

119 

120 g = self.game 

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

122 return act 

123 

124 g.process_action(ReversedScalesAction(tgt, act)) 

125 

126 return act 

127 

128 

129class SadistAction(UserAction): 

130 def __init__(self, source, target): 

131 self.source = source 

132 self.target = target 

133 

134 def apply_action(self): 

135 g = self.game 

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

137 tgt.tags['sadist_target'] = False 

138 g.process_action(Damage(src, tgt, 1)) 

139 return True 

140 

141 

142class SadistHandler(THBEventHandler): 

143 interested = ['action_after', 'action_before'] 

144 card_usage = 'drop' 

145 execute_before = ['WineHandler'] 

146 execute_after = ['DeathHandler'] 

147 

148 def handle(self, evt_type, act): 

149 if evt_type == 'action_after' and isinstance(act, PlayerDeath): 

150 src = act.source 

151 if not src or not src.has_skill(Sadist): 

152 return act 

153 

154 g = self.game 

155 dist = LaunchCard.calc_distance(g, src, AttackCard()) 

156 candidates = [k for k, v in dist.items() if v <= 0 and k is not src] 

157 

158 if not candidates: 

159 return act 

160 

161 pl = user_choose_players(self, src, candidates) 

162 if pl: 162 ↛ 178line 162 didn't jump to line 178, because the condition on line 162 was never false

163 self.game.process_action(SadistAction(src, pl[0])) 

164 

165 elif evt_type == 'action_before' and isinstance(act, Damage): 

166 src = act.source 

167 tgt = act.target 

168 

169 if not src or src is tgt: 

170 return act 

171 

172 if not src.has_skill(Sadist): 

173 return act 

174 

175 if tgt.life == 1: 

176 act.amount += 1 

177 

178 return act 

179 

180 def choose_player_target(self, pl): 

181 return pl[-1:], len(pl) 

182 

183 

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

185class Yuuka(Character): 

186 skills = [ReversedScales, Sadist] 

187 eventhandlers = [ReversedScalesHandler, SadistHandler] 

188 maxlife = 4 

189 

190 

191@register_character_to('kof') 

192class YuukaKOF(Character): 

193 skills = [ReversedScales, SadistKOF] 

194 eventhandlers = [ReversedScalesHandler, SadistKOFHandler] 

195 maxlife = 4