# Coverage for thb/characters/youmu.py : 23%

## 105 statements 37 run 68 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

3# -- stdlib --

4# -- third party --

5# -- own --

6 from thb.actions import ActionStage, Damage, DropCards, UserAction, migrate_cards

7 from thb.actions import random_choose_card

8 from thb.cards.base import Skill

9 from thb.cards.classes import Attack, BaseDuel, LaunchGraze, UseAttack, t_None

10 from thb.characters.base import Character, register_character_to

11 from thb.inputlets import ChooseIndividualCardInputlet

12 from thb.mode import THBEventHandler

13 from utils.misc import classmix

14

15

16# -- code --

17 class MijincihangzhanAttack(Attack):

18 pass

19

20

21 class MijincihangzhanDuelMixin(object):

22 # 迷津慈航斩 弹幕战

23 def apply_action(self):

24 g = self.game

25 source = self.source

26 target = self.target

27

28 d = (source, target)

29 while True:

30 d = (d[1], d[0])

31 if d[1].has_skill(Nitoryuu):

32 if not (

33 g.process_action(UseAttack(d[0])) and

34 g.process_action(UseAttack(d[0]))

35 ): break

36 else:

37 if not g.process_action(UseAttack(d[0])): break

38

39 g.process_action(Damage(d[1], d[0], amount=1))

40 return d[1] is source

41

42

43 class NitoryuuWearEquipmentAction(UserAction):

44 def __init__(self, source, target, card):

45 self.source = source

46 self.target = target

47 self.card = card

48

49 def apply_action(self):

50 g = self.game

51 card = self.card

52 tgt = self.target

53 g = self.game

54

55 weapons = [e for e in tgt.equips if e.equipment_category == 'weapon']

56 if len(weapons) > 1:

57 e = g.user_input([tgt], ChooseIndividualCardInputlet(self, weapons))

58 e = e or random_choose_card(g, [weapons])

59 g.process_action(DropCards(tgt, tgt, [e]))

60

61 migrate_cards([card], tgt.equips)

62

63 return True

64

65

66 class NitoryuuWearEquipmentHandler(THBEventHandler):

67 interested = ['wear_equipment']

68

69 def handle(self, evt_type, arg):

70 we, tgt, c, rst = arg

71 if not evt_type == 'wear_equipment': return arg

72 if not tgt.has_skill(Nitoryuu): return arg

73 if 'equipment' not in c.category: return arg

74 if c.equipment_category != 'weapon': return arg

75

76 g = self.game

77 g.process_action(NitoryuuWearEquipmentAction(tgt, tgt, c))

78 return we, tgt, c, 'handled'

79

80

81 class YoumuHandler(THBEventHandler):

82 interested = ['action_apply', 'action_before', 'attack_aftergraze', 'card_migration']

83 execute_before = ['ScarletRhapsodySwordHandler', 'LaevateinHandler', 'HouraiJewelHandler']

84 execute_after = ['VitalityHandler']

85

86 def handle(self, evt_type, act):

87 if evt_type == 'action_before':

88 if isinstance(act, Attack):

89 if not act.source.has_skill(Mijincihangzhan): return act

90 act.__class__ = classmix(MijincihangzhanAttack, act.__class__)

91 elif isinstance(act, BaseDuel):

92 if not isinstance(act, MijincihangzhanDuelMixin):

93 act.__class__ = classmix(MijincihangzhanDuelMixin, act.__class__)

94

95 elif evt_type == 'action_apply' and isinstance(act, ActionStage):

96 p = act.target

97 p.tags['vitality'] += bool(p.has_skill(Nitoryuu) and self.weapons(p) >= 2)

98

99 elif evt_type == 'card_migration':

100

101 act, cards, _from, to, _ = arg = act

102

103 for cl in (_from, to):

104 if cl.type != 'equips': continue

105 p = cl.owner

106 if not p.has_skill(Nitoryuu): continue

107

108 n = self.weapons(p)

109 dn = len(cards)

110 if not any(getattr(c, 'equipment_category', None) == 'weapon' for c in cards): continue

111

112 if cl is _from and (dn + n) >= 2 and n <= 1:

113 adjust = -1

114 elif cl is to and (n - dn) <= 1 and n >= 2:

115 adjust = 1

116 else:

117 adjust = 0

118

119 p.tags['vitality'] += adjust

120

121 return arg

122

123 elif evt_type == 'attack_aftergraze':

124 act, rst = arg = act

125 if rst: return arg

126 if not isinstance(act, MijincihangzhanAttack): return arg

127

128 g = self.game

129 return act, not g.process_action(LaunchGraze(act.target))

130

131 return act

132

133 @staticmethod

134 def weapons(p):

135 return sum([c.equipment_category == 'weapon' for c in p.equips])

136

137

138 class Mijincihangzhan(Skill):

139 # 迷津慈航斩

140 associated_action = None

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

142 target = t_None()

143

144

145 class Nitoryuu(Skill):

146 # 二刀流

147 associated_action = None

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

149 target = t_None()

150

151 def check(self):

152 return not self.associated_cards

153

154

155# @register_character_to('common')

156 class Youmu(Character):

157 skills = [Mijincihangzhan, Nitoryuu]

158 eventhandlers = [YoumuHandler, NitoryuuWearEquipmentHandler]

159 maxlife = 4