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 annotations 

3 

4# -- stdlib -- 

5from typing import TYPE_CHECKING 

6 

7# -- third party -- 

8# -- own -- 

9from game.base import ActionShootdown 

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

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

12from thb.cards.basic import Attack 

13from thb.cards.definition import AttackCard, RejectCard 

14from thb.cards.spellcard import BaseDuel 

15from thb.characters.base import Character, register_character_to 

16from thb.mode import THBEventHandler 

17 

18# -- typing -- 

19if TYPE_CHECKING: 

20 from thb.thbkof import THBattleKOF # noqa: F401 

21 

22 

23# -- code -- 

24class DarknessDuel(BaseDuel): 

25 pass 

26 

27 

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

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

86class DarknessKOF(Skill): 

87 associated_action = None 

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

89 target = t_None() 

90 

91 

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

100class DarknessKOFLimit(ActionShootdown): 

101 pass 

102 

103 

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

141class Cheating(Skill): 

142 associated_action = None 

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

144 target = t_None() 

145 

146 

147class CheatingDrawCards(DrawCards): 

148 pass 

149 

150 

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

165class Rumia(Character): 

166 skills = [Darkness, Cheating] 

167 eventhandlers = [CheatingHandler] 

168 maxlife = 3 

169 

170 

171@register_character_to('kof') 

172class RumiaKOF(Character): 

173 skills = [DarknessKOF, Cheating] 

174 eventhandlers = [DarknessKOFHandler, CheatingHandler] 

175 maxlife = 3