Coverage for thb/characters/youmu.py : 23%
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 -*-
3# -- stdlib --
4# -- third party --
5# -- own --
6from thb.actions import ActionStage, Damage, DropCards, UserAction, migrate_cards
7from thb.actions import random_choose_card
8from thb.cards.base import Skill
9from thb.cards.classes import Attack, BaseDuel, LaunchGraze, UseAttack, t_None
10from thb.characters.base import Character, register_character_to
11from thb.inputlets import ChooseIndividualCardInputlet
12from thb.mode import THBEventHandler
13from utils.misc import classmix
16# -- code --
17class MijincihangzhanAttack(Attack):
18 pass
21class MijincihangzhanDuelMixin(object):
22 # 迷津慈航斩 弹幕战
23 def apply_action(self):
24 g = self.game
25 source = self.source
26 target = self.target
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
39 g.process_action(Damage(d[1], d[0], amount=1))
40 return d[1] is source
43class NitoryuuWearEquipmentAction(UserAction):
44 def __init__(self, source, target, card):
45 self.source = source
46 self.target = target
47 self.card = card
49 def apply_action(self):
50 g = self.game
51 card = self.card
52 tgt = self.target
53 g = self.game
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]))
61 migrate_cards([card], tgt.equips)
63 return True
66class NitoryuuWearEquipmentHandler(THBEventHandler):
67 interested = ['wear_equipment']
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
76 g = self.game
77 g.process_action(NitoryuuWearEquipmentAction(tgt, tgt, c))
78 return we, tgt, c, 'handled'
81class YoumuHandler(THBEventHandler):
82 interested = ['action_apply', 'action_before', 'attack_aftergraze', 'card_migration']
83 execute_before = ['ScarletRhapsodySwordHandler', 'LaevateinHandler', 'HouraiJewelHandler']
84 execute_after = ['VitalityHandler']
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__)
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)
99 elif evt_type == 'card_migration':
101 act, cards, _from, to, _ = arg = act
103 for cl in (_from, to):
104 if cl.type != 'equips': continue
105 p = cl.owner
106 if not p.has_skill(Nitoryuu): continue
108 n = self.weapons(p)
109 dn = len(cards)
110 if not any(getattr(c, 'equipment_category', None) == 'weapon' for c in cards): continue
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
119 p.tags['vitality'] += adjust
121 return arg
123 elif evt_type == 'attack_aftergraze':
124 act, rst = arg = act
125 if rst: return arg
126 if not isinstance(act, MijincihangzhanAttack): return arg
128 g = self.game
129 return act, not g.process_action(LaunchGraze(act.target))
131 return act
133 @staticmethod
134 def weapons(p):
135 return sum([c.equipment_category == 'weapon' for c in p.equips])
138class Mijincihangzhan(Skill):
139 # 迷津慈航斩
140 associated_action = None
141 skill_category = ['character', 'passive', 'compulsory']
142 target = t_None()
145class Nitoryuu(Skill):
146 # 二刀流
147 associated_action = None
148 skill_category = ['character', 'passive', 'compulsory']
149 target = t_None()
151 def check(self):
152 return not self.associated_cards
155# @register_character_to('common')
156class Youmu(Character):
157 skills = [Mijincihangzhan, Nitoryuu]
158 eventhandlers = [YoumuHandler, NitoryuuWearEquipmentHandler]
159 maxlife = 4