Coverage for thb/characters/reisen.py : 98%
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 game.base import ActionShootdown
7from thb.actions import ActionStageLaunchCard, Damage, LaunchCard, PlayerTurn, UserAction
8from thb.cards.base import Skill
9from thb.cards.classes import AttackCard, DuelCard, Heal, HealCard, PhysicalCard, t_None
10from thb.characters.base import Character, register_character_to
11from thb.inputlets import ChooseOptionInputlet
12from thb.mode import THBEventHandler
15# -- code --
16class Lunatic(Skill):
17 associated_action = None
18 skill_category = ['character', 'passive']
19 target = t_None()
22class Discarder(Skill):
23 associated_action = None
24 distance = 1
25 skill_category = ['character', 'passive']
26 target = t_None()
29class MahjongDrug(Skill):
30 associated_action = None
31 skill_category = ['character', 'passive']
32 target = t_None()
35class LunaticAction(UserAction):
36 def apply_action(self):
37 self.target.skills.append(Discarder)
38 self.target.tags['reisen_discarder'] = True # for tag
39 return True
42class LunaticHandler(THBEventHandler):
43 interested = ['action_after']
45 def handle(self, evt_type, act):
46 if evt_type == 'action_after' and isinstance(act, Damage):
47 src = act.source
48 if not src: return act
49 if not src.has_skill(Lunatic): return act
51 tgt = act.target
52 if tgt.dead or tgt.has_skill(Discarder): return act
54 g = self.game
55 for lc in reversed(g.action_stack): 55 ↛ 59line 55 didn't jump to line 59, because the loop on line 55 didn't complete
56 if isinstance(lc, LaunchCard):
57 break
58 else:
59 return act
61 c = lc.card
62 if not (c.is_card(AttackCard) or c.is_card(DuelCard)):
63 return act
65 if g.user_input([src], ChooseOptionInputlet(self, (False, True))):
66 g.process_action(LunaticAction(src, tgt))
68 return act
71class DiscarderAttackOnly(ActionShootdown):
72 pass
75class DiscarderDistanceLimit(ActionShootdown):
76 pass
79class DiscarderHandler(THBEventHandler):
80 interested = ['action_after', 'action_shootdown']
82 def handle(self, evt_type, act):
83 if evt_type == 'action_shootdown' and isinstance(act, ActionStageLaunchCard):
84 src = act.source
85 if not src.has_skill(Discarder): return act
86 g = self.game
87 current = PlayerTurn.get_current(g).target
88 if src is not current: return act 88 ↛ exitline 88 didn't return from function 'handle', because the return on line 88 wasn't executed
90 self.card = c = act.card
91 if not c.is_card(AttackCard):
92 if c.is_card(PhysicalCard) or 'treat_as' in c.category:
93 raise DiscarderAttackOnly
94 else:
95 return act
97 dist = LaunchCard.calc_distance(g, src, Discarder(src))
98 dist.pop(src, '')
99 nearest = max(min(dist.values()), 0)
100 avail = {p for p in dist if dist[p] <= nearest}
102 if not set(act.target_list) <= avail:
103 raise DiscarderDistanceLimit
105 elif evt_type == 'action_after' and isinstance(act, PlayerTurn):
106 tgt = act.target
107 if tgt.has_skill(Discarder):
108 tgt.skills.remove(Discarder)
109 tgt.tags['reisen_discarder'] = False # for tag
111 return act
114class MahjongDrugAction(UserAction):
115 def apply_action(self):
116 self.target.tags['wine'] = True
117 return True
119 def is_valid(self):
120 return not self.target.dead
123class MahjongDrugHandler(THBEventHandler):
124 interested = ['action_after']
126 def handle(self, evt_type, act):
127 if evt_type == 'action_after' and isinstance(act, Heal):
128 tgt = act.target
129 if not tgt.has_skill(MahjongDrug): return act
130 card = getattr(act, 'associated_card', None)
131 if not card or not card.is_card(HealCard): return act
133 g = self.game
134 if g.user_input([tgt], ChooseOptionInputlet(self, (False, True))):
135 g.process_action(MahjongDrugAction(tgt, tgt))
137 return act
140@register_character_to('common', '-kof')
141class Reisen(Character):
142 skills = [Lunatic, MahjongDrug]
143 eventhandlers = [DiscarderHandler, LunaticHandler, MahjongDrugHandler]
144 maxlife = 4
147@register_character_to('kof')
148class ReisenKOF(Character):
149 skills = [Lunatic]
150 eventhandlers = [DiscarderHandler, LunaticHandler]
151 maxlife = 4