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

5# -- third party -- 

6# -- own -- 

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

8from thb.actions import random_choose_card 

9from thb.cards.base import Skill 

10from thb.cards.classes import Attack, BaseDuel, InstantSpellCardAction, LaunchGraze, UseAttack 

11from thb.cards.classes import t_None 

12from thb.characters.base import Character 

13from thb.inputlets import ChooseIndividualCardInputlet 

14from thb.mode import THBEventHandler 

15from utils.misc import classmix 

16 

17 

18# -- code -- 

19class MijincihangzhanAttack(Attack): 

20 pass 

21 

22 

23class MijincihangzhanDuelMixin(InstantSpellCardAction): 

24 # 迷津慈航斩 弹幕战 

25 def apply_action(self): 

26 g = self.game 

27 source = self.source 

28 target = self.target 

29 

30 d = (source, target) 

31 while True: 

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

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

34 if not ( 

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

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

37 ): break 

38 else: 

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

40 

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

42 return d[1] is source 

43 

44 

45class NitoryuuWearEquipmentAction(UserAction): 

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

47 self.source = source 

48 self.target = target 

49 self.card = card 

50 

51 def apply_action(self): 

52 g = self.game 

53 card = self.card 

54 tgt = self.target 

55 g = self.game 

56 

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

58 if len(weapons) > 1: 

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

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

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

62 

63 migrate_cards([card], tgt.equips) 

64 

65 return True 

66 

67 

68class NitoryuuWearEquipmentHandler(THBEventHandler): 

69 interested = ['wear_equipment'] 

70 

71 def handle(self, evt_type, arg): 

72 we, tgt, c, rst = arg 

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

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

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

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

77 

78 g = self.game 

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

80 return we, tgt, c, 'handled' 

81 

82 

83class YoumuHandler(THBEventHandler): 

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

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

86 execute_after = ['VitalityHandler'] 

87 

88 def handle(self, evt_type, act): 

89 if evt_type == 'action_before': 

90 if isinstance(act, Attack): 

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

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

93 elif isinstance(act, BaseDuel): 

94 if not isinstance(act, MijincihangzhanDuelMixin): 

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

96 

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

98 p = act.target 

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

100 

101 elif evt_type == 'card_migration': 

102 

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

104 

105 for cl in (_from, to): 

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

107 p = cl.owner 

108 if not p.has_skill(Nitoryuu): continue 

109 

110 n = self.weapons(p) 

111 dn = len(cards) 

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

113 

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

115 adjust = -1 

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

117 adjust = 1 

118 else: 

119 adjust = 0 

120 

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

122 

123 return arg 

124 

125 elif evt_type == 'attack_aftergraze': 

126 act, rst = arg = act 

127 if rst: return arg 

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

129 

130 g = self.game 

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

132 

133 return act 

134 

135 @staticmethod 

136 def weapons(p): 

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

138 

139 

140class Mijincihangzhan(Skill): 

141 # 迷津慈航斩 

142 associated_action = None 

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

144 target = t_None() 

145 

146 

147class Nitoryuu(Skill): 

148 # 二刀流 

149 associated_action = None 

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

151 target = t_None() 

152 

153 def check(self): 

154 return not self.associated_cards 

155 

156 

157# @register_character_to('common') 

158class Youmu(Character): 

159 skills = [Mijincihangzhan, Nitoryuu] 

160 eventhandlers = [YoumuHandler, NitoryuuWearEquipmentHandler] 

161 maxlife = 4