Coverage for thb/characters/chen.py : 25%
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 DrawCards, ForEach, LaunchCard, PlayerTurn, UserAction
8from thb.cards.base import Skill
9from thb.cards.classes import AttackCard, DollControlCard, Heal, InstantSpellCardAction, RejectCard
10from thb.cards.classes import t_OtherOne
11from thb.characters.base import Character, register_character_to
12from thb.inputlets import ChooseOptionInputlet
13from thb.mode import THBEventHandler
16# -- code --
17class FlyingSkandaAction(ForEach):
19 def prepare(self):
20 sk = self.associated_card
21 assert isinstance(sk, FlyingSkanda)
22 card = sk.associated_cards[0]
23 action = card.associated_action
24 assert action
25 self.action_cls = action
27 def is_valid(self):
28 p = self.source
29 if p.tags['turn_count'] <= p.tags['flying_skanda']:
30 return False
31 if any(t.dead for t in self.target_list):
32 return False
33 return True
35 def get_actual_action(self, act):
36 return None
39class FlyingSkanda(Skill):
40 associated_action = FlyingSkandaAction
41 skill_category = ['character', 'active']
42 usage = 'launch'
44 def target(self, src, tl):
45 tl = [ch for ch in tl if not ch.dead]
46 cl = self.associated_cards
47 if not cl: return ([], False)
48 c = cl[0]
49 if len(tl) < 2:
50 return c.target(src, tl)
51 else:
52 rst = c.target(src, tl[:-1])
53 a = tl[-1]
54 if a is src:
55 return rst[0], False
56 else:
57 return rst[0] + [a], rst[1]
59 @property
60 def distance(self):
61 cl = self.associated_cards
62 if not cl: return 0
63 return getattr(cl[0], 'distance', 99999)
65 def check(self):
66 cl = self.associated_cards
67 if len(cl) != 1: return False
68 c = cl[0]
69 if c.is_card(AttackCard): return True
71 if c.is_card(DollControlCard): return False
72 if c.is_card(RejectCard): return False
74 act = c.associated_action
75 if not act: return False
76 if not issubclass(act, InstantSpellCardAction): return False
78 return True
80 def is_card(self, cls):
81 cl = self.associated_cards
82 if cl and cl[0].is_card(cls): return True
83 return isinstance(self, cls)
86class FlyingSkandaHandler(THBEventHandler):
87 interested = ['action_after']
89 def handle(self, evt_type, act):
90 if evt_type == 'action_after' and isinstance(act, LaunchCard):
91 if not act.card.is_card(FlyingSkanda): return act
92 act.source.tags['flying_skanda'] = act.source.tags['turn_count']
93 return act
96class ShikigamiAction(UserAction):
97 def apply_action(self):
98 tgt = self.target
99 src = self.source
101 g = self.game
103 if tgt.life < tgt.maxlife and g.user_input(
104 [tgt], ChooseOptionInputlet(self, (False, True))
105 ):
106 g.process_action(Heal(src, tgt))
107 else:
108 g.process_action(DrawCards(tgt, 2))
110 tgt.tags['shikigami_target'] = src
111 src.tags['shikigami_target'] = tgt
112 src.tags['shikigami_tag'] = src.tags['turn_count']
114 return True
116 def is_valid(self):
117 return 'shikigami_tag' not in self.source.tags
120class Shikigami(Skill):
121 associated_action = ShikigamiAction
122 skill_category = ['character', 'active', 'once']
123 target = t_OtherOne()
125 def check(self):
126 return not self.associated_cards
129class ShikigamiHandler(THBEventHandler):
130 interested = ['post_calcdistance']
132 def handle(self, evt_type, arg):
133 if evt_type == 'post_calcdistance':
134 src, card, dist = arg
135 if not card.is_card(AttackCard): return arg
137 tgt = src.tags.get('shikigami_target')
138 if not tgt or tgt.dead: return arg
140 g = self.game
141 current = PlayerTurn.get_current(g).target
142 if current is not src: return arg
144 origin = src if 'shikigami_tag' in src.tags else tgt
145 if origin.tags['shikigami_tag'] != origin.tags['turn_count']:
146 return arg
148 dist2 = LaunchCard.calc_raw_distance(g, tgt, AttackCard())
150 for k in dist2:
151 if dist[k] > 0 and dist2[k] <= 1:
152 dist[k] = 0
154 return arg
157@register_character_to('common', '-kof')
158class Chen(Character):
159 skills = [FlyingSkanda, Shikigami]
160 eventhandlers = [FlyingSkandaHandler, ShikigamiHandler]
161 maxlife = 4