Coverage for thb/characters/youmu.py : 24%
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
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
18# -- code --
19class MijincihangzhanAttack(Attack):
20 pass
23class MijincihangzhanDuelMixin(InstantSpellCardAction):
24 # 迷津慈航斩 弹幕战
25 def apply_action(self):
26 g = self.game
27 source = self.source
28 target = self.target
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
41 g.process_action(Damage(d[1], d[0], amount=1))
42 return d[1] is source
45class NitoryuuWearEquipmentAction(UserAction):
46 def __init__(self, source, target, card):
47 self.source = source
48 self.target = target
49 self.card = card
51 def apply_action(self):
52 g = self.game
53 card = self.card
54 tgt = self.target
55 g = self.game
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]))
63 migrate_cards([card], tgt.equips)
65 return True
68class NitoryuuWearEquipmentHandler(THBEventHandler):
69 interested = ['wear_equipment']
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
78 g = self.game
79 g.process_action(NitoryuuWearEquipmentAction(tgt, tgt, c))
80 return we, tgt, c, 'handled'
83class YoumuHandler(THBEventHandler):
84 interested = ['action_apply', 'action_before', 'attack_aftergraze', 'card_migration']
85 execute_before = ['ScarletRhapsodySwordHandler', 'LaevateinHandler', 'HouraiJewelHandler']
86 execute_after = ['VitalityHandler']
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__)
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)
101 elif evt_type == 'card_migration':
103 act, cards, _from, to, _ = arg = act
105 for cl in (_from, to):
106 if cl.type != 'equips': continue
107 p = cl.owner
108 if not p.has_skill(Nitoryuu): continue
110 n = self.weapons(p)
111 dn = len(cards)
112 if not any(getattr(c, 'equipment_category', None) == 'weapon' for c in cards): continue
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
121 p.tags['vitality'] += adjust
123 return arg
125 elif evt_type == 'attack_aftergraze':
126 act, rst = arg = act
127 if rst: return arg
128 if not isinstance(act, MijincihangzhanAttack): return arg
130 g = self.game
131 return act, not g.process_action(LaunchGraze(act.target))
133 return act
135 @staticmethod
136 def weapons(p):
137 return sum([c.equipment_category == 'weapon' for c in p.equips])
140class Mijincihangzhan(Skill):
141 # 迷津慈航斩
142 associated_action = None
143 skill_category = ['character', 'passive', 'compulsory']
144 target = t_None()
147class Nitoryuu(Skill):
148 # 二刀流
149 associated_action = None
150 skill_category = ['character', 'passive', 'compulsory']
151 target = t_None()
153 def check(self):
154 return not self.associated_cards
157# @register_character_to('common')
158class Youmu(Character):
159 skills = [Mijincihangzhan, Nitoryuu]
160 eventhandlers = [YoumuHandler, NitoryuuWearEquipmentHandler]
161 maxlife = 4